Skip to content

Releases

1.0.0

Choose a tag to compare

@github-actions github-actions released this 05 Nov 14:20

The first desktop release. GT7 Datalogger now comes as one download for macOS (Apple
silicon), Windows and Linux, with no Docker, Python or terminal: it runs the same
server and shows the same dashboard in your browser
(Desktop app). Docker, Raspberry Pi and source
installs get the same server changes. If you reach the logger through a reverse proxy
by a DNS name, set GT7_TRUSTED_HOSTS before upgrading (see Security).

The macOS app is signed and notarized. The Windows files are not code-signed yet, so
SmartScreen warns before the installer runs (More info, then Run anyway), and
the Linux files have no .asc signatures yet; check either against SHA256SUMS.txt.

Added

  • The app can tell you a newer release is out (#196). With Check for updates
    on, the server asks GitHub Releases once a day which release is the latest and, if
    it is above the running version, reports it (version and link) in
    /api/admin/stats under update; POST /api/admin/update-check asks straight
    away. Notify only: nothing is downloaded. Versions are compared by full release
    precedence, so 0.9.0-rc.1 < 0.9.0-rc.2 < 0.9.0 and a lower or equal version is
    never offered; update_channel stable asks for the latest release only, and
    prerelease takes the highest of the last twenty, release candidates included.
    The check is off by default (the desktop launcher turns it on), applies the moment
    it is switched, remembers its answer and its ETag across restarts so a restart does
    not ask again, is silent when it fails, and waits for GitHub's rate limit to reset
    when it is told to. The configuration docs now list everything the app fetches on
    its own: the car list, the first-start track pull and this.

  • A first-run wizard explains the network prompts before they appear (#191).
    Opening the app with setup not yet completed (the desktop app, or any install
    that has recorded nothing) lands on #/welcome; a bookmark or a deep link is
    never taken over, and an existing install with sessions keeps its start page. In
    the desktop app it first says how the app works: it records in the background,
    with its icon in the menu bar or the notification area, and this page is its
    dashboard in the browser, which can be closed at any time. It asks PlayStation
    or Try the demo: the demo stays on the simulator and offers
    its scenarios. The PlayStation path says what this computer will ask first (the
    Windows Firewall prompt, the macOS Local Network alert, the firewalld/ufw hint on
    Linux), then switches to the PlayStation source, which is what raises the prompt,
    searches for the console and saves the address, with manual entry and the PS5
    menu path when the search finds nothing. Listener and heartbeat errors become
    specific help (another program on UDP 33740, Local Network denied, a firewall, GT7
    not running). A live check waits for telemetry and offers packet format A when
    packets arrive but do not decode. The desktop app then asks whether phones and
    tablets may connect; finishing turns LAN access on or leaves it off, shows the
    admin token it created, a QR code of the dashboard's LAN address and this
    computer's own address to bookmark. Finishing,
    and Skip setup, complete setup, which starts recording.

  • The UI knows how it is installed (#190). Advice that assumed Docker now
    follows the install kind from /api/health: the unreachable page, the mDNS and
    127.0.0.1 help under Settings › Phone app, the Race Engineer note, and the
    Advanced line for an environment-only setting (the desktop app restarts its
    server by itself). A new Settings › About shows the version, how it runs, the
    data folder and log file, the update status, and that the app is unofficial and
    not affiliated with Sony Interactive Entertainment or Polyphony Digital. With LAN
    access off, Settings › Phone app and the layout builder say so, with a Let my
    phone/tablet connect
    switch, instead of showing an address nothing can reach.
    Copy buttons work on a plain-HTTP LAN address, where the clipboard API does not
    exist: they fall back to the old copy command, and failing that select the text.
    A listener that could not start, a failing heartbeat and laps that could not be
    saved show in a strip under the status bar on every view, and a banner says when
    a newer version is out, once the server reports one. A request the server's guard
    refuses (LAN access off, an untrusted Host, a cross-site request) shows the
    server's reason instead of "admin token rejected", and on the desktop app
    Settings › Access says the computer's own browser never needs the token.

  • One data folder for everything the app writes (GT7_DATA_DIR). The database,
    track bundles, survey logs, sync state, backups and the installation's identity all
    sit in one folder; unset, that is the database's own folder, exactly as before. With
    it set the database defaults to gt7.db inside it, so a launcher can place an
    install with one variable instead of a working directory (#178).

  • One version, read the same way everywhere. The version the server reports over
    mDNS, sends the sync service and stamps into compiled track documents now comes from
    a committed backend/app/_version.py; the three readers it replaces disagreed in a
    dev venv. python scripts/version.py bump X.Y.Z rewrites the five places a release
    touches and check fails when they drift apart (#179).

  • A log file, when you ask for one (GT7_LOG_FILE). Lines go to a file as well,
    rotated at 5 MB with four old files kept, uvicorn's own lines — a port already in
    use, a failed start — included. Docker users can set
    GT7_LOG_FILE=/data/logs/gt7.log (#180).

  • /api/health says what is answering. It returned only {"status": "ok"}, so a
    launcher, a phone or a second copy could not tell this server from anything else on
    port 8000. It now adds app, version, install_kind (desktop, docker or
    source) and the database's schema revision beside the newest this build knows (#184).

  • A first-run setup marker. GET /api/admin/setup reports where setup stands and
    POST /api/admin/setup/complete stores the marker and starts recording. With
    GT7_FORCE_SIM=firstrun (set by the desktop app) the server starts on the simulator
    with mDNS and recording off until then, so no network prompt appears before the
    first-run wizard explains it (#184).

  • LAN access is one live switch (GT7_LAN_ACCESS). Off, only the computer
    running the server can use it (other devices get 403 lan_off) and mDNS stops
    announcing it; on — the default, as before — phones and tablets connect. It is
    checked on every request, so changing it restarts nothing and drops no lap. Finishing
    first-run setup with LAN access on creates an admin token when there is none, which
    other devices then need for changes; reads and the live stream stay open. In the
    desktop app the computer's own browser needs no token (#195).

  • The database is copied before a new version upgrades it. When a start finds the
    schema behind this build's, it first copies the database, with SQLite's backup API,
    to backups/pre-upgrade-<time>-<revision>/ in the data folder, beside a
    manifest.json saying which version made the copy, the revisions it goes from and
    to, how many sessions, laps, tracks, settings and layouts it holds, and its
    quick_check verdict. The copy is written as .partial and takes its name only once
    the manifest is in it, so a start killed half way never leaves something that looks
    like a good backup. One copy is kept, three on the desktop app. Without 2.2 times the
    database's size free, the start logs how much is needed and stops rather than
    upgrade with no way back (#182).

  • Setup asks about units and background requests. The first-run wizard has a
    Preferences step: Race Engineer units, chosen from the browser's region (miles in the
    US, UK, Liberia and Myanmar), and switches for the daily update check and the car-list
    refresh. The car-list refresh had no off switch at all; GT7_CAR_REFRESH=false (Settings
    › Advanced) now keeps the bundled inventory until you press Update car database (#191).

  • The desktop app's launcher and build (desktop/). One executable in three
    modes: a supervisor with a menu-bar item (macOS) or tray icon (Windows) that holds
    the port and runs the server as a child of itself, restarting it if it crashes or
    stops answering; --headless for systemd; and --server, the child. One app per data
    folder, a saved port with 8001–8009 as fallback, "already running" when Docker holds
    the port, Start at login, Open data folder and logs, a phone/tablet toggle, and
    Windows firewall repair. The app, its shortcuts, the macOS menu bar and the Windows
    tray carry the GT7 Datalogger mark, made from desktop/icons/source/ by
    desktop/icons/make_icons.py. desktop/scripts/build.py freezes it with PyInstaller and
    desktop/ci/smoke.py checks a build end to end; nothing of it reaches the Docker
    image (#192, #193, #194).

  • Windows and Linux packaging for the desktop app. Windows gets an Inno Setup
    installer, GT7-Datalogger-Windows-x64-Setup.exe, which installs for everyone by
    default (or "for me only") into the same folder every version, so the firewall
    rules it adds for the app (UDP and TCP, local subnet, private and public networks)
    survive updates. It closes a running copy before updating, after saying a session
    being recorded will be closed; offers Start at login and Check for updates daily;
    and leaves the data folder alone on uninstall. A portable zip ships beside it, and
    desktop/windows/package.ps1 -Sign signs every .exe, .dll and .pyd and then the
    installer and uninstaller, through Azure Artifact Signing, SignPath or a .pfx, with
    a Defender scan that fails the build on any detection. Linux gets an AppIm...

Read more

0.9.0

Choose a tag to compare

@jbhoorasingh jbhoorasingh released this 30 Oct 13:49
bffdd44

Added

  • A synced session gets its circuit even when its first lap was not a whole
    one.
    The session is announced to the sync service with its first lap, and the
    circuit is identified from a whole lap; a race's grid start, a pit-out lap or
    logging that began mid-lap is not one, so the summary went without the circuit
    and the session stayed unnamed on the service even after the next lap named it.
    The circuit is now owed once it is known: it goes on its own straight away to a
    service that takes that (track_on_patch among its sessions hints, from
    gt7-sync-service #37), and always with the drive's totals, which an older
    service ignores. The service fills a session's circuit only while it has none,
    and so does the logger, so a session keeps the circuit it opened with. A server
    that refuses the circuit costs the session nothing: the laps and totals still go.

  • Sportsland SUGO is recognised. GT7 added SUGO International Racing Course in
    its October update, after the shipped catalog was generated, so sessions there stayed
    unnamed. The catalog now carries it (42 tracks, 122 configurations) and the shipped
    signatures include it, built from the lap zetetos/gt-telemetry published; the
    re-vendored file also brings the surveys gt7-datalogger-track-data has merged since
    the last copy: 26 configurations now take their geometry from a surveyed road
    instead of one captured lap, and 80 are recognised in all (#170).

  • Spanish, Brazilian Portuguese and Japanese. A language menu in the status bar
    (and on /engineer) sets this device's language; Auto follows the browser. The
    Race Engineer speaks and captions its callouts in it, with that language's own
    wording rather than a translated English sentence ("Tiempo de vuelta, un minuto
    32,5
    ", "ラップタイム、1分32秒5"), and its Voice panel can pick a different
    Callout language from the interface's. Voices are listed for the callout
    language; a device with none for it speaks the English and keeps the captions
    translated. The whole interface is translated — every view, the dash and the OBS
    overlays — except the setting names in Settings › Advanced, which the server
    sends in English; dates follow the language too. A copied overlay or dash URL
    carries the language (&lang=es), since an OBS source has no menu. Callout
    message_args now describe the English sentence exactly — null for a clause it
    leaves out, plus the sector-voice precision, corner names and spoken units — which is
    what the browser words a translation from; the Analysis coaching notes carry the same
    message_key/message_args, and a Tracks layout suggestion its reasoning as
    match (#85).

  • Backup: one file for a whole install. Settings › Data › Back up makes
    gt7-backup-<date>.zip from the parts you pick: Data (every session and lap, as
    a copy of the database), Surveys (track bundles, corrections, survey logs, car
    widths and the install's source id), Config (saved settings, without
    credentials), Dash/OBS (overlay and dash layouts) and Tokens (the webhook URL
    and sync token, off by default). A manifest.json records the app version, the
    database's schema revision and what each part holds. The database is copied a few
    megabytes at a time, so the recorder keeps saving laps while a backup is made, and
    compacted, so deleted laps do not travel with it. The archive is laid out like the
    data folder, so it can also go back by hand. The lap exports that used to sit under
    Back up are now Export laps (#161).

  • Restore a backup. Settings › Data › Restore uploads a backup, lists the
    parts it holds with what each would do here, and applies only the ones ticked.
    Data replaces the recordings: the backup's database is unpacked, checked,
    upgraded if an older version made it, and swapped in with the recorder paused only
    for the swap; the replaced database is kept as gt7.db.before-restore-<time>, and
    this install's saved settings and layouts stay. A backup from a newer version is
    refused for Data, with the version it came from. Surveys merge as an import
    does, adding corrections, survey logs and car widths where this install has none;
    Install identity (source-id.json) is its own switch, on by default only for
    an install with no recordings yet. Config merges through the same checks as
    Settings › Advanced, with the per-machine settings (source, console IP, ports,
    simulator scenario, LAN announcement) listed but off by default. Dash/OBS
    merges by name, and Tokens go into secrets.json only when ticked. Laps are
    then re-judged against the surveys here in the background (#161).

  • Sector times from the Race Engineer. With Sector announcements on
    (Settings › Race Engineer, off by default), the engineer calls each sector as
    you complete it, against the coaching reference: the delta, the sector time
    or both, sector by sector or cumulative. It needs the circuit's sector
    boundaries, authored in Tracks, where the checklist now has a Sectors
    row. The same switch sets how many decimals (1 to 3) and whether rounded or
    truncated, for sector and lap time announcements alike. Contributed by
    @Marstiphal (#165).

  • Sector times on the Analysis lap strip. Each sector on the lap strip shows its
    time, for the compared lap or the reference when none is compared, with the delta
    to the reference beside it; zoomed to a sector, the map's callout shows the same.
    The times run the lap's own clock from the line to the line, so they add up to the
    lap time. A lap whose clock did not run the whole lap (a recording joined part way
    round, a stop the logger skipped) shows none, and a circuit without authored sectors
    is timed in thirds of the lap, marked ~. Contributed by @Marstiphal (#166).

  • Sector comparison and theoretical best. A new Analysis panel beside Sector times
    sets the reference lap's sectors against the session's best of each, with the time
    the reference lost to the best in every sector, and adds the best sectors up into a
    theoretical best lap and how far it is under the reference. Bests come only from laps
    that count; a reference from another session has no comparison, since the bests are
    this session's. Contributed by @Marstiphal (#167).

  • Replay Recording for leaderboard replays. Some GT7 leaderboard replays stream
    without the on-track flag, so the recorder skipped every packet and the lap never
    reached replay salvage. A Replay Recording switch on the Live dashboard (off by
    default, and off again after a restart) records them anyway: replay packets are
    sampled while the car is moving, a stop in the replay keeps its time, and paused,
    loading and idle-menu packets are still skipped. While it is on, every lap completes
    only through replay salvage, so GT7's own lap time has to vouch for it, and the
    sessions it opens are excluded from bests. Turn it on before the replay starts and
    off before driving; it applies to new sessions, not the one already open
    (POST /api/control/replay-recording, admin). The switch is translated, and a toggle
    the server refuses (a protected server without the admin token) shows why in a toast.
    Contributed by @Marstiphal (#171, #87).

Fixed

  • Sector times put time the recording missed into the last sector. Analysis ›
    Sector times shares GT7's lap time out by the lap's own clock, and the last sector
    takes the remainder. A lap the logger joined part way round, or whose clock froze
    through a stop or an outage it skipped, has a clock that falls short of the lap time,
    so the sectors where it lost time read short and the last sector long by everything
    missed — up to six minutes on recorded laps. A lap whose clock does not agree with its lap
    time, within the window a salvaged lap has to meet (500 ms, or 0.5 % of the lap),
    now shows no sector times. Partial laps timed line to line keep theirs (#168).

  • The Race Engineer said "ten tenths" for a gap of 950–999 ms. A lap delta,
    personal-best gain, pace drop or corner loss chose tenths before rounding, so just
    under a second came out as "ten tenths slower". It now rounds first and says "one
    second", like a lap time carries 59.96 s to the next minute.

0.8.1

Choose a tag to compare

@jbhoorasingh jbhoorasingh released this 21 Oct 17:27
20c2f7b

Added

  • Front wheel angle and wheelbase on every lap. Laps recorded on packet C
    carry a new optional sample column, wheel_angle: the mean of the two front
    road wheels' steering angles in radians, as GT7 broadcasts them — what the
    tyres did, beside steer, what the steering wheel did. Each lap also stores
    the car's wheelbase_m. Together they give the yaw rate the car would have
    with no slip (speed × wheel_angle ÷ wheelbase), the reference for measuring
    understeer and oversteer, and show where the front wheels stop turning while
    the steering input keeps rising. Both travel in lap export and import, the
    session archive and (wheel_angle, as "Front Wheel Angle") the CSV export;
    the lap file stays at version 2. Laps recorded without packet C, and every
    lap stored before, have neither. The simulator sends both. Adding them
    migrates the database (0013), so an older version cannot open it afterwards
    (#154).
  • Understeer and oversteer against the front wheels. Analysis has three new
    channels for packet-C recordings: Front wheel angle, beside Steering, where the
    input rising while the wheels go flat is the steering lock; Kinematic yaw, the
    rotation the front wheels asked for (speed × wheel angle ÷ wheelbase); and Yaw
    balance
    , the measured yaw rate minus it — below zero understeer, above zero
    oversteer. The two are worked out on the server from the full 60 Hz ticks, not the
    charts' resampling, and are absent from laps without packet C. The corner report
    card gains Yaw ÷ wheels (under 1 understeer, over 1 oversteer) and, where a
    corner ran out of lock, Lock m; the lap analysis document carries both under
    each corner's balance and the car's wheelbase_m. No learned baseline is needed,
    so they are there from the first lap (#155).
  • Engine torque. Laps recorded on the ~ packet or wider carry a new optional
    column, engine_torque: the engine torque being delivered, normalized, as GT7
    broadcasts it — negative on the overrun, 0 with the clutch in. It is in the
    Analysis channel picker (Engine) and the CSV export. The live packet also decodes
    the powertrain byte (powertrain_flags) and the energy-recovery flag
    (energy_recovery_available). All three meanings come from the community's
    decoding of the packet, not from Polyphony (#150).
  • Chase a lap. Race Engineer coaching can compare against a stored lap of
    the circuit you are driving instead of your session best: Coaching
    reference
    on /engineer, then Chase a lap. A quicker lap of your own
    takes over, falling back to the chosen lap if it stops counting. The choice
    survives race restarts and ends on a new car or circuit. New WebSocket
    message set_engineer_reference; race_engineer_status gains
    reference_mode, reference_lap_id and reference_time_ms. Contributed by
    @Marstiphal (#152).
  • Split view in Analysis. Split, beside Follow on the race line map,
    puts four charts of your choosing next to the map on a wide screen, sharing
    its cursor and zoom; the full chart stack stays below. Remembered on this
    device. Contributed by @Marstiphal (#156).
  • Every lap's values on the race line map. Pointing at the reference line
    shows a readout there: the time diff and each chart panel, one column per
    lap the map shows, as the chart tooltip lists them. It works in the
    full-screen map too, where the charts are out of sight, and Hover
    readout
    in the Layers menu switches it off. Contributed by @Marstiphal
    (#159).

Fixed

  • A pit stop before the timing line split a race into several sessions. Where
    the pit box comes before the line (Montreal), the car rejoins on the lap it stopped
    on. The stop was salvaged as a finished lap whenever the in-lap's length matched a
    time GT7 still reported, which left a phantom lap carrying an earlier lap's time,
    and the session then ended because the lap counter had not moved on: one 12-lap
    race with two stops became three sessions. A lap salvaged during a stop is now held
    until driving resumes. The same car on the same lap was a stop mid-lap, and the lap
    goes on to complete with GT7's own time; the next lap continues the session as
    before; anything else, or a stop longer than 90 s, emits the salvage as it used
    to be at once. A held salvage is saved when the server shuts down (#153).
  • mDNS pointed phones at a port they could not reach under ./dev.sh. The dev
    script ran uvicorn without --host, so the API listened on 127.0.0.1 while the
    advertisement and the Phone app QR code gave the LAN address. The dev script now
    binds every interface, as Docker and python -m app.main already did; a server
    bound to loopback only is not advertised, and Settings › Phone app says why
    instead of showing a code that would not connect (#151).
  • Brake applied is labelled as what it is: the brake actually applied after ABS,
    which GT7 sends in live driving only (#150).
  • Follow zoomed the race line in on a hover. The Follow camera tracked any
    cursor, so with Follow on, moving the mouse across a chart dropped the map
    into a close-up — constantly in split view, where the charts sit beside it.
    It now tracks the playhead only, as its tooltip always said (#157).

Security

  • The webhook URL and sync token are no longer stored in the database. Both are
    credentials, and the database is the file people copy when asked for their data.
    Settings now saves them in secrets.json beside the database, created readable by
    its owner only; every other setting stays in the database. On the first start of
    this version, values an older version saved are moved there and wiped from the
    database file, including the bytes a plain delete would have left behind. Nothing
    changes for sync or notifications, and GT7_SYNC_TOKEN and GT7_WEBHOOK_URL in the
    environment work as before. Settings › Data links to a new
    Sharing your data section on what to
    send instead of the database (#94).

0.8.0

Choose a tag to compare

@jbhoorasingh jbhoorasingh released this 15 Oct 20:02
12d214f

Added

  • Sector times. (#22) A new Analysis panel splits every lap of the
    session at the circuit's sectors, the best of each sector and the best lap
    in purple. Sector boundaries are placed on the Tracks page beside the
    corners — each one is where a sector ends — by clicking the map, or from
    the sector times a race screen showed for one of your laps, which say
    where that lap was when each sector ended. They are stored in the track
    bundle as an optional sectors key, so they travel with export, import
    and sync. A circuit without them is split into thirds of the lap, the
    boundaries taken from the session's quickest lap as places on the road
    and found on every other lap, so a wider line does not move a split.
    GET /api/analysis/sectors serves the figures; the comparison reply
    carries the sectors on the reference lap's axis. Track sync sends the
    boundaries with the bundle; a server that does not keep them yet drops
    the key, and once it advertises max_sectors the next Sync now
    re-sends every bundle that has some, so none placed earlier is lost.

  • Every setting in Settings. (#140) A new Advanced section lists every
    setting the server has, each with its environment variable, default, where
    its value comes from (set here, the environment, or the default) and
    whether a change applies at once or at the next start, plus a reset
    that hands it back to the environment. The stream rate, CORS origins,
    UDP ports, simulator scenario, sync live rate, car and track files and
    the admin token can now be changed without editing the environment;
    only the bind host, port and database path stay environment-only.
    GET/PUT /api/admin/config serve it, and the configuration
    reference's tables are generated from the same list, so the documented
    defaults are the shipped ones.

  • Live client protocol. (#141) A client of /ws/live can open with hello
    and choose its own telemetry rate (up to the full 60 Hz), a full frame
    carrying every packet field, and which events it receives. The server
    answers with welcome (protocol version, server version, capabilities).
    This is what the phone app will use. Clients that say nothing,
    the browser UI included, get exactly the stream they always did. The
    protocol is published as JSON Schema under
    docs/reference/schemas/ws/ along with the REST API's openapi.json,
    both generated from the server's models.

  • Phone discovery and pull. (#142) The server announces itself on
    the LAN over mDNS as _gt7dl._tcp, carrying the protocol version
    (GT7_MDNS, on by default, switchable live). The new Phone app
    section in Settings shows whether it is being announced, and the server's
    address as a QR code for networks where multicast does not reach.
    GET /api/sessions/changes?since= returns the sessions changed since a
    revision and the ids of every session that still exists, so a client
    keeping a copy pulls only what changed. Every write to a session or its
    laps bumps the session's new revision.

  • Two receivers at once. (#144) Documented: the console streams to
    every client sending heartbeats, so two dataloggers, or a datalogger and
    the phone, can capture the same drive.

  • Gearing sawtooth. (#107) Under the Analysis Gearing panel's ratio
    table, a chart of speed against rpm: a line per gear from standstill to
    the redline, and the lap's own samples over them coloured by gear, so
    where each gear was shifted, how far the revs drop across each ratio gap
    and whether top gear is ever reached all read off one chart. The panel
    follows the corner report card's focus lap, and draws the reference
    behind in grey when its gearbox differs. GT7 sends no final drive, so
    the lines are fitted to the lap's own samples; GT7's top speed stands in
    when a lap gives no consistent fit.

  • Suggested gear, recorded and judged. (#108) The gear GT7 suggests on
    its HUD, the → 3 the Live view's gear widget already showed, is now
    kept on every lap as the suggested_gear sample column. It holds 15
    where GT7 suggested nothing, and a lap on which it suggested nothing at
    all keeps no column. The Analysis Gear panel draws it dashed beside
    each lap's gear and shades the corners taken a gear higher, and the
    playback strip shows it beside the gear. A corner is judged at its
    slowest point against the last gear GT7 suggested on the way in. The
    Tuning panel counts the reference lap's corners a gear high, and
    the Sessions lap table gains a Gear high column for every lap,
    measured against the session's quickest counting lap.
    corner_report rows and the lap analysis document's speed block carry
    suggested_gear and gear_high, GET /api/analysis/gear-choice serves
    the per-lap counts, and the CSV export has a Suggested Gear channel. The
    lap file's version is unchanged. The simulator now suggests gears, and on
    about half its laps holds a gear too many through one corner. When GT7
    fills the suggestion has not been checked against a console yet.

Changed

  • CORS origins apply live. GT7_CORS_ORIGINS is read per request, so
    changing it in Settings takes effect without a restart. The API reference
    no longer claims CORS is open to every origin; it never was by default.
  • The Analysis race line map. (#102) The reference line is coloured by
    a lens — Inputs, Speed, Gain / loss against the compared lap, Tire temp
    (the hottest tire, on the Live tiles' 55 / 95 °C bands) or F−R temp
    (front minus rear, even within ±3 °C, full colour from 8) — and drawn as
    one line rather than a trail of dots. The lens is remembered on the
    device and carried in the Analysis link as lens=; the tire lenses are
    greyed out on laps recorded before per-corner channels. The header's row of
    toggles is a Layers menu with a switch for everything the map draws
    besides the line: the surveyed road, corner numbers, the other laps with
    their apex speeds and brake points, and the markers. Corner numbers are
    bare labels beside the apex. Zooming: drag along the line, ⌘/Ctrl +
    wheel about the pointer, [ and ] through the corners, Esc or a
    double-click out; the window animates, a locator inset shows where on
    the lap it is, apex badges give every lap's minimum speed through a
    corner in view, and a callout says what the compared lap did there. A
    corner's window now starts where the reference began braking for it.
  • The lap strip. A bar under the map — the lap unrolled, coloured like
    the line — carries the track's sectors as S1…Sn buttons (replacing the
    thirds buttons) and the corner numbers, and the zoom window to drag,
    resize and slide. A compact copy is pinned over the charts, so the zoom
    stays in reach with every channel on. The map's borders are drawn as
    simplified polylines instead of a segment per metre.
  • The corner report card reads in track order by default, with a sort
    switch for biggest loss first.

Fixed

  • Speed at redline on laps recorded before 0.7.0. The Gearing panel
    read under 6 km/h for them: it took the stored top speed as top gear's
    speed at the redline, and those laps hold a ratio there (#128). The
    speeds now come from the same fit as the chart (#107), and the top speed
    is hidden where it is not one.
  • Auto-discovery finds the console again on a new address. With no console
    IP set, the heartbeat followed the first console that answered and kept going
    to that address for good, so a PlayStation that came back from rest mode, a
    router reboot or a lease change on another DHCP address never streamed again
    until Find console was pressed. Once the stream has been quiet for 5 s
    the heartbeat is broadcast again (and still sent to the last known address),
    and whichever address answers takes the stream over. With a console IP set
    the heartbeat still goes only to it, and Find console still keeps a second
    console it wakes out of a live stream.
  • Race opening laps no longer inflate consistency. Confirmed lap 1s from
    standing and rolling starts are excluded from bests with the reason race start,
    so the existing consistency calculation leaves them out too. Full-lap geometry
    and telemetry are preserved, and the exclusion can be overridden. Existing
    sessions with a recorded race result are updated once, preserving manual rulings.
  • A pit stop no longer splits a race in two. (#136) Going through the
    pits could close a completed lap and end its session at once, so one
    continuous race became two sessions. The decision now waits until driving
    resumes: the same car carrying on into the next lap keeps the session,
    anything else starts a new one. Replays still split, and a race finish
    seen while the car is inactive keeps its result in the original session.

0.7.0

Choose a tag to compare

@jbhoorasingh jbhoorasingh released this 28 Sep 04:33
eaf67e5

Changed

  • The session being recorded can be deleted once recording is paused.
    (#130, contributed by @NikiforovG) Until now it could not be deleted until
    the next session started, which is never, if you stop driving and switch
    the console off. Pause recording with ● REC and it can go. Its
    unfinished lap goes with it, and recording again starts a fresh session.
    While recording is on it stays protected, through pauses, pit stops and
    connection drops alike. Deleting now shares one lock with packet
    processing, lap saves, best-lap rulings, the recording switch and Log
    lap now
    , so a delete waits for a lap still being saved rather than
    racing it.
  • Web UI usability revamp. Admin is renamed Settings. It now has a
    section rail, a health strip, and a single Apply bar that sends every
    buffered edit in one request, replacing seven separate Apply buttons. The
    overlay builder moves to its own Overlays tab. Sessions becomes a
    master–detail view with a lap-time chart, a bulk-action bar and
    auto-hidden constant columns. Tracks gains a "Needs you" list and a
    readiness checklist. Live is denser: shift lights, a Δ card and a pinned
    in-progress lap. /engineer and /dash are rebuilt for touch. New
    route-level pages cover 404, a locked server, server errors, an
    unreachable server and a silent console. The status bar shows telemetry
    as a labelled dot. The fastest lap is purple everywhere. #/admin links
    still work.
  • The simulated car has a heading. The simulator sent every packet with
    a velocity of (speed, 0, 0) and no orientation, whichever way the car was
    going. It now sends the velocity along the path it is driving and the
    car's orientation as GT7 does, turned from the path by a body slip that
    points the nose out of a slow corner and into a fast one, so the body slip
    channel can be seen in sim mode. build_packet takes an orientation.
  • The Race Engineer's coaching compares laps by place, and knows which
    corner a braking zone belongs to.
    (#110) Two things were wrong with
    "you braked twelve metres earlier into turn five". The laps were compared
    at equal distance, and a lap's own distance drifts from another's by a
    median 2.9 m and up to 64 m — the Analysis view has lined laps up by
    position since 0.6, the engineer had not. And the braking point was "the
    first brake application in the 250 m before the corner's entry", which
    through a sequence is often the corner before's: on the best laps of nine
    stored sessions it disagreed with where the corner's braking zone began at
    41 of 105 corners. Coaching now puts every lap on the reference lap's
    axis before comparing (off the event loop, at the lap boundary), and takes
    what a lap did at a corner from processing/corner_metrics — each brake
    application belongs to one corner, the first apex its midpoint has not
    reached, and a corner's braking zone is the one that took the most speed
    off. The lap analysis document uses the same definitions, so the two
    cannot disagree. Replayed over 21 stored sessions the number of coaching
    notes is unchanged (120) and 59 are word for word the same; gone are the
    likes of "you are braking early into turn ten, about two hundred thirteen
    meters". Thresholds for what is worth saying are unchanged.
  • SQLAlchemy 2.1 or newer is required. The repository layer's Select
    and Row annotations follow 2.1's variadic generics (a five-column
    projection is Row[int, int, int, bool, bool]; a row of any shape is
    Row[*tuple[Any, ...]]). No query changed.
  • Compiled borders are smoothed. A border record sits on a 1 m grid, and
    an edge record and a straddle record of the same kerb disagree by up to
    a metre about where it is, so an ordered border stepped sideways wherever
    the kind changed — nicks in the drawn line, and a road whose edge moved a
    metre in a metre. The compiler now smooths each surveyed run with Taubin's
    λ|μ pass, which does not pull curves towards their inside the way an
    average does: against corners whose true border is known it stays within
    0.35 m on everything from a 3 m kerb to an 80 m sweeper, where a ±8 m
    moving average cuts 2 m off the kerb. Ends of a run stay where the survey
    stopped, nothing is smoothed across a gap, no vertex moves more than
    0.75 m from its record (under track_limits' edge margin), and the bundle
    itself is never rewritten. Over the 24 circuits in the shared map: 3 103
    kinks to 19, every gap span unchanged, coverage within 0.3 of a point.
    compile_bundle(doc, smooth=False) compiles the evidence exactly as
    recorded, and the document's new smoothing key says which it got.
    Compiled format 3, so every stored compile is rebuilt once.

Fixed

  • A lap's top speed is a speed. Its gearing.top_speed was written
    from transmission_top_speed, which GT7 sends as a ratio (2.3 for a tuned
    AE86), so the gearing panel's "est. @ redline" column read 1–2 km/h for
    every real recording. It now comes from GT7's own estimate,
    calculated_max_speed, on both the live and salvaged lap paths (#128).
    The simulator had hidden this by sending 290 in the ratio field. Laps
    recorded before keep the ratio in their stored gearing.
  • "Delete all recorded data" while recording no longer strands the next
    laps.
    It cleared the tables but left the recorder holding the wiped
    session, so the laps driven next were saved against a session that no
    longer existed. It now takes the same lock and resets the recorder the way
    deleting the current session does (#130), and recording carries on into a
    fresh session.
  • The fastest lap is purple everywhere. The overlay and dash times
    widget, the Sessions list and the Bests board still drew it in the accent
    blue. On the Bests board a slower time's gap is neutral grey rather than
    red. A fastest colour joins the theme, with the same value as the
    charts' FASTEST_COLOR.
  • The position widget no longer reads "P-1/0" outside a race. GT7 sends
    -1 and a field of 0 in practice, time trial and menus. The widget now shows
    a dash until there is a real position.
  • Pitting on a lap's last stretch no longer splits the race. GT7
    reports the line crossing into the next lap while the car is in the pit
    lane, where it is not "on track". The lap was salvaged from its GT7 time,
    which is right, but every salvaged lap also ended the session. That rule is
    for a replay whose stream breaks off, and here it opened a new session for
    the rest of the race. The next lap number in the same car now keeps the
    session going. A replay, where the counter jumps elsewhere or the car
    changes, still gets its own session.
  • A deleted session's id is never given to a new one. SQLite numbered a
    new session one past the largest id left, so after "Delete all recorded
    data", or deleting the newest session, the next drive reused an old id.
    The sync client still held a record under that id, so a race's laps were
    sent into the deleted qualifier's server session and replaced its laps.
    Session ids now use AUTOINCREMENT (migration 0011, a rebuild of the small
    sessions table). Deleting a session, or everything, now also clears the
    sync client's record of it, and a session that opens always starts a
    fresh sync record.
  • Analysis no longer sticks on a session that has been deleted. The tab
    remembers the last session it showed. If that session had since been
    deleted, a newer one never appeared until it was opened from Sessions. It
    now falls back to the newest session with laps.
  • Menus, pit stops and pauses no longer merge or split sessions. (#120,
    contributed by @NikiforovG) GT7 keeps streaming while the car is not being
    driven, and those packets carry lap counters of their own: 0 or -1 in a
    menu, 0 in the pits. The lap processor read them as it read driving. A
    race that ended at lap 12 and went through a menu at -1 left the counter
    parked there, so the next race's lap 1 was not seen as a reset and the two
    races were recorded as one session; a pit interruption that read
    6 → 0 → 6 was seen as a reset and split one race in two. A car change or
    a lap reset is now confirmed only by a packet that is on track, unpaused
    and has a lap number of 0 or more. Inactive packets keep the last driving
    lap and its buffer, and never open a session by themselves. Two ways of
    finishing a lap still accept them: the time-validated replay salvage, and
    the final lap's +1 step from the same car, which records the race result
    even when the finishing packet has already cleared the on-track flag. The
    packet counter is followed through loading screens as well, so their
    frames add nothing to the lap clock. A new session logs why it began.
  • The session being recorded cannot be deleted from under the recorder.
    (#121, contributed by @NikiforovG) Deleting the current session removed its
    row while the recorder kept its id: laps driven afterwards were saved
    against a session that no longer existed, and a race's finishing result
    was lost without a word. DELETE /api/sessions/{id} now answers 409
    for the recorder's current session, paused or not, and the Sessions view
    says why. The check is serialized with session creation, so a session
    cannot be deleted in the moment between its row being committed and the
    recorder adopting its id. Every other session deletes as before. The
    current session becomes deletable once the next one has started, or after
    a restart.
  • Analysis no longer shows the previous session under a new session's
    name.
    Picking a session with no completed lap yet from the Analysis
    dropdown — which is every session until its first lap is finished, so
    exactly the one you have just started driving — changed the title and
    nothing else: the lap chips, the map, the charts and the address bar all
    stayed on the session that had been open, its laps re...
Read more

0.6.2

Choose a tag to compare

@jbhoorasingh jbhoorasingh released this 20 Sep 03:33
f10c840

Added

  • Events and driver aids on the race-line map. (#103, #104) The map in
    Analysis gains two layers, each with a toggle in its header that only
    appears when the selected laps can fill it, remembered on the device.
    Events marks where each detected lockup ◆, wheelspin ●, bottoming ✚
    and kerb strike ✖ began, filled with the lap's colour so the same braking
    zone going wrong on three laps is visible as three marks in one place.
    Hovering a marker names the lap, the wheels and the severity in words
    ("slowest wheel at 62% of road speed"); clicking one zooms every panel to
    the event with 60 m either side. Suspension events are detected per wheel,
    so same-type events beginning within 6 m of each other draw as one marker
    that names all the wheels. TCS rings every sample where traction
    control was cutting power, in the lap's colour and hollow so the input
    zone underneath stays readable; ASM does the same with squares and
    starts off. Both follow the zoom, draw in the full-screen map, and the
    key under the map lists only what is drawn in the current window.

  • Session consistency, as a figure and a chart. (#112) Each session row
    carries its consistency under the lap-time sparkline — ±0.42 s · 0.4%,
    the standard deviation of the lap times and that as a share of the median
    lap, green under 0.5 % and amber from 1.5 %. Analysis gains a Lap times
    — this session
    panel: every lap as a point against lap number, a line
    through the laps that count, the median dashed and a one-sigma band
    around it, with the spread, median and best beneath. Both are taken over
    the laps that count toward bests and no others, the same verdict the bests
    board acts on, and need three of them: a pit out-lap, a race's lap 1 and
    laps excluded by hand are drawn hollow and left out of the figure, and a
    lap too slow for the scale is pinned to the top edge so one out-lap cannot
    flatten the rest. Points in the current comparison take their chart
    colour, and clicking a point adds the lap to the comparison or removes it.

  • Sessions and live sync. (#79) The sync client now sends the other two
    data types the service takes, each behind its own toggle in Admin → Sync,
    off by default and offered only when the server lists it. Sessions
    sends your own laps as you drive — each lap as the gt7-datalogger-lap
    document Export writes, against a session the service opens for the
    drive — and the totals when the drive ends. The session is announced with
    its first lap, not at its start, so a stint that never completes a lap
    never reaches the server and the summary carries the circuit and its
    layout id, which are only known one lap in. Laps queue in
    data/sync-sessions.json while the service is away and flush in order
    when it answers or at the next start; a lap ruled in or out of the bests
    by hand is sent again with its new verdict; a session the service no
    longer has (deleted in its portal, or expired) is closed here and said
    so. Live holds one WebSocket to the service while the car is on track
    and sends where it is about four times a second (GT7_SYNC_LIVE_HZ, no
    faster than the server's ceiling): position, speed, gear, lap and lap
    time, downsampled from the 60 Hz feed and never queued. The socket opens
    on the first on-track packet and closes after five minutes without one;
    the Sync panel shows the spectate URL and how many are watching. A
    stream an administrator closes, or another logger on the account
    replaces, is held for a quarter of an hour rather than fought over. The
    Admin push now takes ?type= and, blank, flushes every active type.
    GT7_SYNC_SESSIONS, GT7_SYNC_LIVE, GT7_SYNC_LIVE_HZ.

  • Discard a lap or the run while surveying. (#98) A spin that laid
    border points across the gravel, or a boundary marked on the wrong side
    for half a lap, used to be in the bundle for good — the merge only adds,
    and the only way back was to out-vote the bad metres by re-driving them
    twice. The Survey view has Discard lap, which throws away what this
    run has surveyed in the current lap so far and carries on, and Discard
    run…
    , which throws away everything the run has gathered; neither stops
    the survey. Only this run's votes go: a metre another run or another
    installation had mapped keeps that evidence and loses this run's vote on
    it. Evidence the autosave already wrote is backed out of the bundle, the
    circuit's laps are re-judged as after any bundle write, and the run's
    JSONL records the discard so a log assigned later does not bring the lap
    back. New endpoint POST /api/survey/discard; the survey status carries
    lap, lap_votes, run_votes and discards.

Fixed

  • ASM coming on no longer reads as traction control. The aids column
    is a bitmask and was resampled onto the comparison's 5 m grid by linear
    interpolation like every other channel, so ASM switching on (0 → 2)
    passed through 1, the TCS bit, and the Throttle panel shaded a sliver of
    TCS at every ASM onset; TCS together with the rev limiter (9) falling
    back to nothing could pass through the handbrake bit the same way. aids
    now takes the nearest sample's value, as surface already did. Stored
    laps are unaffected — the per-lap TCS and ASM percentages were always
    computed from the raw ticks.

  • Where a circuit crosses over itself, both levels are surveyed and
    judged.
    (#96) A border record was identified by its plan cell alone, so
    Suzuka's bridge and the road beneath it were one metre of road: whichever
    level was surveyed first kept the cell, the other's geometry was thrown
    away, its votes were counted against the survivor, the compiled borders
    zigzagged between the two, and a lap over the bridge was judged against
    whichever level had won — flagged beyond the surveyed edge while on the
    road. Bundle format v5: one record per metre per side per road
    level
    , levels told apart by an elevation difference over 3 m. The figure
    comes from the collected bundles — 0.72 m is the widest elevation spread
    between same-side neighbours, 0.18 m between raw survey marks in one
    cell; banking is 5.5 m across the road at Daytona but is never compared
    within a cell. A record without elevation merges as it always did. The
    border ordering refuses a next cell the road could not have climbed to,
    the across-the-road pairing prefers its own level, each road quad carries
    its elevation envelope (compiled geometry v2) and the survey judge places
    a sample by its elevation: on the deck is on the deck, and a car on an
    unsurveyed road under a surveyed bridge reads unknown, never off. Laps now
    store pos_y beside pos_x/pos_z. Laps recorded before this release
    carry no elevation
    and are judged on plan alone, which at a crossover
    means against both levels at once — they get the benefit of the doubt
    there and cannot be re-judged any tighter. A v4 bundle upgrades untouched;
    a crossover it merged before v5 has already lost its second level, which
    only re-driving or a replace import (#93) brings back. stacked_cells in
    the bundle stats counts the metres where both levels are present. The
    data repo's copy of the format moves to v5 alongside.

Changed

  • TODO.md is gone. The feature list the project started from had been
    overtaken by the issue tracker: most of it shipped, and what had not is
    now filed as issues (#22, #101–#112). The "tiers" note in the
    derived-channels docs points there instead.

0.6.1

Choose a tag to compare

@jbhoorasingh jbhoorasingh released this 17 Sep 19:06
48a13c6

Fixed

  • Laps are re-judged when a track's survey changes. (#91) A lap's
    verdict against the surveyed edges — off_survey_count, and the
    clean_lap it feeds — was decided once, when the lap was saved, against
    the bundle as it was then. Fixing a bad survey afterwards changed nothing:
    the only re-judge covered the live session, and only at the moment its
    circuit was identified. Every bundle write now queues a pass over every
    lap ever driven on the circuit, across sessions and across spellings of
    its name: a survey run's saves (two minutes after the last one, so a
    running survey's autosave never triggers a pass over the whole history),
    a log assigned, a shared bundle pulled, an import, a rename (the label
    left behind too), a delete — after which the verdicts go back to unknown
    rather than keeping a judgement from geometry that no longer exists.
    Identifying old sessions judges their laps too. The pass runs in the
    background; Re-check laps on a Tracks row forces it and says how many
    verdicts changed. New endpoint POST /api/track-bundles/{slug}/rejudge.
  • A survey-caused "not clean" flag can be cleared again. (#92)
    clean_lap was folded one-way: an excursion past the surveyed edge set it
    false, and a re-judge that found none carried the stored value forward, so
    a lap a bad survey spoiled stayed spoiled whatever was corrected later. It
    is now derived from both counts every time — clean when GT7's surface
    flags saw nothing and nothing ran past the surveyed edge — by one function
    the live lap and the re-judge share. A lap the old flag left behind (count
    zero, clean false) is repaired by the next pass.

0.6.0

Choose a tag to compare

@jbhoorasingh jbhoorasingh released this 17 Sep 02:40
5857952

Added

  • A sync client for contributing surveys. (#79) Pulling shared bundles
    has worked since #47, but sending a survey back was a clone-the-repo-and-
    open-a-PR job. Admin → Sync now takes a server address and a token
    (the address field also accepts the gt7sync://…?token=… connection
    string the service issues, split into the two), keeps the token on its
    own, masked in the UI, sent only as a Bearer header and never logged,
    asks the server what data types it accepts, and shows a toggle per type
    under a master switch, all off by default. The one type this release sends
    is tracks: every survey bundle whose official layout has been
    confirmed — corner labels included — uploaded once it has been left alone
    for ten minutes after a change. A running survey's once-a-minute autosave
    keeps resetting that clock, so a run goes up once, after it stops and the
    labelling that follows it; Sync now skips the wait. Nothing is re-sent
    when the evidence has not changed since the server last accepted it. Uploads run in the background with retry and exponential
    backoff; a refused document is remembered with its reason and not retried
    until the bundle changes; a server that stops accepting tracks flips the
    toggle off and says so. Each row of the Tracks view carries a chip — not
    synced — confirm layout
    , queued, syncing, synced with the upload id,
    rejected, error. The client is one transport plus one adapter per data
    type, so sessions and live reuse the plumbing when their server halves
    land. New settings GT7_SYNC_URL, GT7_SYNC_TOKEN, GT7_SYNC_ENABLED,
    GT7_SYNC_TRACKS; new endpoints GET /api/admin/sync, POST /api/admin/sync/test, POST /api/admin/sync/push; /api/track-overview
    rows gain a sync field.

  • An in-app guide to the Analysis view. The view had grown to thirty chart
    channels and a dozen features, and none of them said what they were: a panel
    called "Tire spd / car spd" or a switch called "sync" was left to be
    guessed at. A ? button in the toolbar now opens a short guide — a
    Features tab and a Channels tab, a sentence or two each on what it shows and
    how to read it, what a recording needs to have a channel, which channels are
    on the chart now, a search across both, and a link from every entry to its
    section of the documentation, which stays the long form. The channel picker
    shows the same description on hover and links to the list. The descriptions
    live beside each channel's definition and are required there, and a test
    fails if any documentation link stops landing on a real heading, so the guide
    can't quietly fall behind the app.

  • Laps can be excluded from bests by hand. (#74) Only the partial-lap guard
    could keep a lap off the bests, and it only ever asks one question — did the
    lap cover the whole track? An off-track lap, a lap with contact, or an out-lap
    the guard accepted all went on owning the session best and the Bests board.
    The Sessions lap table now has a Counts checkbox per lap, with a reason
    picker (off-track, contact, restart, dirty, pit-out) beside an excluded one,
    and PATCH /api/laps/{id} behind it. The ruling works both ways — a lap the
    guard wrongly called partial can be counted — and it sits beside the guard's
    verdict rather than over it: the guard keeps re-judging the session as laps
    arrive and can never overwrite a ruling, and clearing one hands the lap back
    to whatever the guard said last. Every consumer of "does this lap count"
    already filtered on one flag, which is now computed from both in SQL, so the
    session best, the Bests board, the class benchmark, the session-summary
    webhook and the Race Engineer's pace and coaching all follow a ruling without
    a change of their own. On the session being driven, the live session best, the
    Δ-best reference and the engineer's coaching reference move on the spot. The
    Bests board says why a quicker time is missing (⊘ 1:28.422 off-track).
    Rulings travel with exported lap files, and so does the guard's verdict: an
    imported pit out-lap stays partial instead of becoming a best on the machine
    it lands on.

  • Time-synced ghosts on the race line. (#75) Every dot on the Analysis map
    sat at the reference car's distance — right for reading the chart delta under
    the cursor, but it never showed where the other car physically was at the same
    moment, which is what makes a gap legible while a lap plays back. The map now
    syncs on time by default: the reference dot stays at the playhead and
    every other lap's dot is drawn where that lap had got to after the same
    elapsed time, interpolated between samples so it glides rather than hops. A
    slower lap trails, a quicker one leads, and the distance between them is the
    gap. sync: Time | Position in the map header switches back to dots level
    with the reference — which, now that compared laps are lined up by place (see
    Fixed), sit on top of it apart from the line each lap took. The choice is
    remembered per device, like Follow; the charts and the other cursor-synced
    panels stay on distance.
    Checked against the raw 60 Hz positions of 1,215 recorded laps (27.7 h), a
    time-synced dot sits a median 7 mm and a p99 25 cm from where the car
    actually was. Where GT7 reset a car mid-lap — a jump of up to 4 km in one
    tick, which the 5 m distance grid cannot represent — the dot holds and then
    jumps, at a moment estimated from the step's speeds, instead of sliding
    across the infield. Every map dot is now placed at the exact cursor rather
    than the nearest 5 m step (that was up to 2.5 m of false gap between the
    reference and a time-synced dot), which also stops the Follow camera
    hopping 5 m at a time during playback.

  • Export a whole session as a ZIP. (#76) Backing up or handing over a
    session meant clicking json on every lap. Export session (and
    GET /api/sessions/{id}/export.zip) now packs every lap's export file and a
    session.json — the session row as the sessions list gives it: car, circuit,
    tags, note, bests exclusion and race result — into one archive. The lap files
    are the single-lap exports unchanged, so each one imports today. Laps are
    read, compressed and written one at a time, off the event loop, and the
    archive spools to disk past 16 MB, so a long endurance stint doesn't have to
    fit in a Raspberry Pi's memory. Importing the archive back as a session is
    the follow-up.

  • Cars describe themselves, and keep themselves current. (#57) The bundled
    car data was 575 rows of id,name — the app could print a name and answer
    nothing else — and it only ever changed when somebody found the admin button,
    which downloaded a third-party mirror of the same list. Cars are now a real
    inventory, generated from Polyphony's own car list and shipped inside the
    package: manufacturer, model year, Gr. category, drivetrain, aspiration,
    displacement, power, torque, weight and dimensions, for 584 cars. It resolves
    from the package rather than the working directory, so a fresh install names
    every car it ships knowing about on its first packet, with no network and no
    setup step. On top of that the app refreshes itself — on first run and weekly
    after that, in the background, never blocking or failing a start — so cars
    added by a GT7 content update arrive on their own. Being offline is not an
    error: the bundled inventory is the floor, and a failed check simply keeps
    it. A refresh only ever adds and updates, so the ten cars GT7 no longer
    publishes keep their names for the sessions that reference them. Sessions
    carry the manufacturer, year, drivetrain and aspiration on the row beside the
    car name — the full published name, model year, category, drivetrain,
    aspiration, displacement, power, torque, weight, dimensions and PP — and
    sessions recorded before this, or before a car was known, are filled in as
    soon as the inventory can answer for them. Laps deliberately store no copy:
    every lap query already joins its session, so lap listings, the Bests board
    and lap detail read the car across a join they were making anyway, and
    GET /api/laps gained manufacturer= and drivetrain= filters on the back
    of it.

  • Circuits name themselves on a fresh install. (#58) Track identification
    needed data only you could produce — a signature exists once somebody names a
    circuit, a survey bundle once somebody maps one — so a new install recognised
    nothing, and every session stayed unnamed with no hint that naming one circuit
    would light up the track badge, the outline, category bests and corner labels.
    The app now ships signatures for 78 GT7 configurations — nine from circuits we
    have surveyed ourselves, the rest from published circuit captures — generated
    offline and vendored so the first packet resolves with no network. They live in the same tracks table as your own and are marked as
    shipped, which is what keeps the two apart: a circuit you named always wins,
    and a re-sync replaces every shipped row and none of yours. The Tracks view
    labels them, and keeps undriven ones out of the table so 78 rows restating the
    catalog cannot bury the rows that mean something.

  • Reverse layouts are told apart from their forward twin. (#58) A reverse
    layout has exactly the same bounding box and length as the layout it reverses,
    so a shipped signature would have named reverse laps after the forward
    configuration — and because bests key on the circuit name, forward and reverse
    times would have pooled and competed for the same personal best. Each shipped
    signature now carries the racing line in driving order, and a lap is walked
    against it to see which way round it went. Not a clockwise test: signed area
    does not survive a crossover, and Suzuka is a figure-eight. Measured over 896
    recorded laps, this moved 10 laps of Deep Forest Reverse off Deep Forest
    Race...

Read more

0.5.0

Choose a tag to compare

@jbhoorasingh jbhoorasingh released this 17 Aug 16:48
d9f38cc

Added

  • The survey compiles into an actual track. (#38, #40) The bundle store
    keeps border evidence as an unordered cloud of voted metre-cells; everything
    downstream wanted them in order. A new compile pass walks each side's
    cells into ordered polylines — 96–99 % of cells chain on the surveyed
    circuits, generally into one closed loop per side — and derives the
    centerline with measured road width and elevation, the road surface as a
    contiguous quad strip, and the finish line. The Analysis map now draws that
    road: on Deep Forest the fill went from 9 paired spans to ~940 quads,
    because the compile pairs a border against the opposite border's curve
    rather than hunting for a cell directly across (which almost never exists —
    the two sides are surveyed on different laps). Unsurveyed stretches are
    never invented: they are flagged as gaps, drawn dashed, and coverage is
    now measured against the boundary itself
    — surveyed metres over total
    boundary metres, gaps and loop-closure in the denominator — shown per
    bundle in the Tracks view. The compiled document is derived data
    (data/track-bundles/compiled/, rebuilt automatically whenever the bundle
    changes), with JSON Schemas published for it and for bundle v4 in the docs.
    Raw survey JSONL logs can now also be downloaded and uploaded, so a run
    recorded on one machine can be replayed into another's bundles.

  • Laps are judged against the surveyed edges, not just the surface
    flags.
    (#41) The surface characters are blind to paved run-off — running
    wide over asphalt reads as tarmac and stays "clean". When a circuit's
    survey resolves at least half its road, each lap's positions are now also
    classified against the compiled road surface: sustained excursions beyond
    the surveyed border count separately (off_survey_count), appear as a
    second figure in the Sessions table, and spoil clean_lap. Unsurveyed
    ground never counts against a lap, and laps recorded before the session
    was identified are re-judged the moment identification names it.

  • The integrated clock now checks itself against GT7's. (#20) Elapsed
    time is integrated from packet ids; packet C also broadcasts the game's own
    live lap clock, decoded and until now unused. The processor tracks how far
    the two drift apart within each lap — surfaced in GET /status next to
    frames_dropped, with a log warning when a lap drifts past 100 ms.
    Diagnostic only: it validates the time axis every chart is drawn from.

  • The race-line map is something you can actually look at. It was a
    360-pixel thumbnail that only the charts could drive, which is not enough
    map for a 5 km circuit. Now: ⤢ opens it full screen, with scroll-to-zoom
    and drag-to-pan (kept out of the rail, where a wheel that sometimes scrolls
    the page and sometimes zooms is worse than one that always scrolls); a
    corner strip under the map takes you to any corner in one click — as does
    clicking the numbered circle on the map — and drives the shared zoom, so
    the charts follow the map into the corner instead of the two disagreeing;
    and the reference lap is drawn as a continuous zone-coloured line rather
    than a dotted trail, because samples land every 5 m and that reads as a line
    across a whole circuit but as scattered dots exactly where you have zoomed in
    to look closely.

    The map is also no longer stretched. A metre across is now a metre
    down — the axis ranges follow the plotting area's pixel aspect, so the shape
    holds in the rail and at full screen alike. Letting each axis fill the box
    independently distorted it by the circuit's aspect ratio: 8 % at Lago
    Maggiore Centre and nearly 3x at Deep Forest.

  • A surveyed circuit now recognises itself. Auto-identification only ever
    matched against signatures written by naming a track by hand, which left a
    hole big enough to make surveying feel broken: survey three circuits, never
    use name track…, and the app has a metre-accurate map of each while still
    failing to recognise the next session driven there — so the track badge, the
    outline under the race line, category bests and corner labels all stay empty
    on a circuit it has mapped in detail. Having surveyed a track and having
    named it were two separate facts and nothing joined them.

    A lap with no matching signature is now compared against the survey
    bundles, which are a strictly better fingerprint than a bounding box — they
    are the road, not a rectangle around it. Matching asks the only question that
    matters, did this lap drive on this surveyed tarmac?, and needs both a
    coverage floor and a clear margin over the runner-up: two configurations of
    one venue share tarmac, and a thin margin means the evidence does not
    actually distinguish them, so the session stays unnamed rather than being
    given a wrong name silently. Thresholds calibrated against 321 real sessions,
    where the scores turn out sharply bimodal with an empty band to put the cut
    in. A signature someone typed still wins outright. (#41)

  • Sessions recorded before a circuit was surveyed can be named in bulk.
    New sessions identify themselves, but history already on disk never got the
    chance — which, for anyone who surveyed a circuit before this shipped, is all
    of it. Tracks → Identify sessions re-runs the match over every unlabelled
    session, reading each one's shortest usable lap rather than a whole
    session's telemetry. (#41)

  • The surveyed road now sits under the race line in Analysis. A racing line
    only means something against the road it was driven on — whether the apex was
    clipped, how much kerb was used, whether there was tarmac left on the exit —
    and until now the map drew the lap floating in empty space. When the
    session's circuit is named and surveyed, the map draws the track beneath
    every lap: road surface, both borders, hand-marked walls in their own colour,
    and the start/finish line. The geometry is compiled server-side
    (/api/track-outline) and cached per bundle revision, because a bundle is up
    to 50,000 border records and the browser has no business downloading a
    circuit's whole survey history to draw a map. Circuits with no bundle answer
    with an empty outline — never having been surveyed is the common case, not an
    error — and the map falls back to exactly what it drew before. (#51, carved
    out of #41)

  • Traction circle (g-g diagram) in the Analysis side rail, from the
    accelerometer GT7 has been broadcasting and this app has been throwing away.
    Every moment of the lap plotted as lateral against longitudinal g, coloured by
    input zone: how much of the ring gets used is the reading, and an empty
    middle-left/middle-right is a car that never brakes and turns at the same
    time. Compared laps overlay as faint dots, the cursor is synced with the
    charts and the map, and the peak g in each direction is called out.

    The scale is checked, not assumed. GT7 documents neither a unit nor a
    sign convention for sway/heave/surge, and a simulator cannot prove
    what a real console sends — which is why #16 said to validate before
    building any UI. So the app validates, per lap, against physics the same
    lap already recorded: lateral against v × ω (with the signed yaw rate
    taken from the driven path, since the stored yaw column is absolute),
    longitudinal against dv/dt. A least-squares slope through the origin
    recovers the unit and the sign at once, so the diagram comes out upright
    whichever way the console counts. When a lap gave too little steady
    cornering or braking to check, the panel says scale unverified rather
    than drawing a confident-looking circle on an unproven scale. (#16)

  • Steering-angle channel. wheel_rotation has been decoded since packet B
    support landed and dropped on the floor ever since. It is now a stored column
    and a chart panel: next to the yaw-rate trace it is what makes understeer
    legible — more lock, no more rotation — along with corrections and
    catch-and-release oversteer. (#15)

  • ABS and TCS intervention, measured instead of inferred. The ~ packet
    format carries the pedal positions after the aids acted on them; plotted
    against the raw pedal the two lines separate exactly where an aid stepped in.
    New channels: Throttle applied, Brake applied, and the two gaps on
    their own — TCS cut and ABS release. The aids bitmask only ever said
    whether an aid was active; this says how much it took. (#18)

  • Car category as a real dimension (#19). The class was already stored and
    already filtered the Sessions list; it is now a server-side filter
    (/api/sessions?category=Gr.3), it survives a session whose first packet
    arrived in a narrower format (the session inherits its laps' class rather than
    sitting outside its own filter), and Analysis shows the class benchmark —
    the fastest full lap ever recorded at this circuit in the same category, the
    gap to the reference lap, and a link to open it (/api/laps/best). Scoped by
    class deliberately: a Gr.3 time and an N100 time around the same corners are
    not the same achievement.

  • Tracks view (new tab): the three sources of track knowledge, joined —
    the DB's named tracks (which is what makes auto-identification work), the
    survey bundles, and the bundled official GT7 catalog. Having one is not
    having the others, and until now nothing said so: that gap is how a survey
    ran for ~55 minutes attached to no circuit at all. Each row shows what is
    present and what is missing (auto-ID, survey, official layout, metres
    mapped, runs and contributing sources, elevation completeness — which only
    fills in by re-driving — finish line located, corners labelled against the
    official turn count) with the action for each gap beside it: assign an
    orphaned run, rename (which merges when the new name is an exi...

Read more

0.4.1

Choose a tag to compare

@jbhoorasingh jbhoorasingh released this 08 Aug 03:48
4f0020b

Fixed

  • Race Engineer voice now works from other devices on the LAN. Opening the
    dashboard from a plain-HTTP address (http://<pi-ip>:8000 — the normal way to
    reach a Raspberry Pi) broke voice output: the browser only provides
    crypto.randomUUID on HTTPS or localhost, so registering the device and claiming
    Use this device for voice output failed silently. The client id now falls back
    to crypto.getRandomValues, which works everywhere.
  • Phone navigation. The header nav drops to its own row on narrow screens
    instead of clipping tab names — Sessions and Admin are reachable on a phone again.
  • Lap colours no longer collide in Analysis. Colours are keyed to the lap id
    six-wise, so laps 6 apart — routinely the "latest vs best" pair — rendered
    identically in the charts, map and chips. Laps compared together now always get
    distinct colours; a lap only changes colour when it collides, and keeps its
    canonical colour everywhere else.
  • /dash and /engineer have a way back to the main app (a small home link);
    the OBS overlay stays chrome-less.
  • #/overlay now routes to the overlay like its #/dash and #/engineer
    siblings, alongside the existing /overlay and #overlay forms.
  • Cross-view links into Analysis keep the chart channel selection (ch= was
    declared but never written), and the S1/S2/S3 zoom buttons' hover style renders
    (its colour token was never defined).