Gran Turismo Telemetry
Python library for interfacing with Polyphony Digital's telemetry service for motion rigs in GT6/GTS/GT7 (maybe older?)
Features
- Playstation IP Address discovery
- Synchronous and asynchronous callbacks with thread pool execution
- Game event observer
- Telemetry as an object or a dictionary
- Configurable callback worker threads for optimal performance
Installation
Install with pip:
pip install gt-telem
Note: The GUI uses heartbeat type "B" to access motion data including steering wheel rotation.
Requirements:
- Gran Turismo 7 running on PlayStation
- Telemetry enabled in GT7 settings
- PlayStation and PC on the same network
- Python 3.7+ with tkinter (included with most Python installations)
Usage
Getting telemetry is fairly straightforward. Here's a simple example that runs the client on a separate thread:
from gt_telem import TurismoClient
from time import sleep
tc = TurismoClient()
tc.start()
for i in range(10):
sleep(1)
print(tc.telemetry.position)
tc.stop()
If you're working inside of an asynchronous framework, use run_async()
from gt_telem import TurismoClient
class MyAsyncClass:
def __init__(self, tc: TurismoClient):
self.tc = tc
self.cancel_tkn: asyncio.Event = None
async def start_telem(self):
await self.tc.run_async(self.cancel_tkn)
Otherwise run like this if you only care for callbacks:
import json
from gt_telem import TurismoClient
from gt_telem.models import Telemetry
# Both sync and async callbacks are supported
async def print_telem_async(t: Telemetry):
print(json.dumps(t.as_dict, indent=4))
def print_telem_sync(t: Telemetry):
print(f"Speed: {t.speed_mps:.2f} m/s")
tc = TurismoClient()
tc.register_callback(print_telem_async) # Async callback
tc.register_callback(print_telem_sync) # Sync callback
tc.run() # Blocking call
The full list of telemetry is available here.
Events
The following events are currently supported:
- gt_telem.events.GameEvents
- on_running - The game has started/is running
- on_in_game_menu - Outside of a race or track screen
- on_at_track - Player has entered a track screen
- on_in_race - Fired when the simulation starts, before player control
- on_paused - When the player pauses the race
- on_race_end - Fires when a player leaves the simulation
- gt_telem.events.RaceEvents
- on_race_start - Fired at the beginning of Lap 1
- on_race_finish - Fired when the last lap is completed (checkered flag)
- on_lap_change - Fires when the lap counter changes (including 0->1)
- on_best_lap_time - A new best lap is set
- on_last_lap_time - A new last lap time is available
- on_track_detected - Track has been detected
- gt_telem.events.DriverEvents
- on_gear_change - A gear has changed
- on_flash_lights - High Beams have been activated
- on_handbrake - Player has utilized handbrake
- on_suggested_gear - Fires when the game suggests a gear change
- on_tcs - Traction Control System activated
- on_asm - Active Stability Management activated
- on_rev_limit - Engine revs exceed threshold
- on_brake - Player depresses brake
- on_throttle - Player depresses throttle
- on_shift_light_low - Engine revs entered lower bound for shift light
- on_shift_light_high - Engine revs exceed upper bound for shift light
Example using Events
Here's a more complex example of a telemetry recorder that hooks into race start, pause, and race end:
from gt_telem import TurismoClient
from gt_telem.events import GameEvents
from gt_telem.errors.playstation_errors import *
class MySimpleTelemetryRecorder():
def __init__(self, tc: TurismoClient):
self.tc = tc
self.storage = []
def start(self):
self.tc.register_callback(MySimpleTelemetryRecorder.receive_telem, [self])
def stop(self):
self.tc.deregister_callback(MySimpleTelemetryRecorder.receive_telem)
# save self.storage somewhere
@staticmethod
async def receive_telem(t, context):
context.storage.append(t)
print(f"{t.engine_rpm}RPM - {t.boost_pressure}kPa")
print(f"Best: {t.best_lap_time}\tLast: {t.last_lap_time}")
if __name__ == "__main__":
try:
# Configure with more workers for heavy telemetry processing
tc = TurismoClient(max_callback_workers=18)
except PlayStationOnStandbyError as e:
print("Turn the playstation on")
print(e)
exit()
except PlayStationNotFoundError as e:
print("Maybe I'm on the wrong network")
print(e)
exit()
ge = GameEvents(tc)
mstr = MySimpleTelemetryRecorder(tc)
ge.on_in_race.append(mstr.start)
ge.on_race_end.append(mstr.stop)
ge.on_paused.append(mstr.stop)
print("Listening for telemetry. CTRL+C to stop")
tc.run()
TurismoClient.run() is a blocking call, but does shut down gracefully when a keyboard interrupt is issued. It also accepts a cancellation token.
Advanced Example
See this jupyter notebook that displays a live race view and how to properly pass a token to shut down gracefully.
Heartbeat Types
Gran Turismo 7 supports different heartbeat message types that provide additional telemetry data. You can specify the heartbeat type when creating a TurismoClient:
from gt_telem import TurismoClient
# Standard heartbeat (default) - 296 bytes
tc_standard = TurismoClient(heartbeat_type="A")
# Motion data heartbeat - 316 bytes with additional motion fields
tc_motion = TurismoClient(heartbeat_type="B")
# Extended data heartbeat - includes filtered inputs and energy recovery
tc_extended = TurismoClient(heartbeat_type="~")
Heartbeat Type "A" (Standard)
This is the default format that provides all the standard telemetry data. Compatible with most existing GT7 telemetry applications.
Heartbeat Type "B" (Motion Data)
Adds 5 additional motion-related fields:
wheel_rotation_radians- Wheel rotation in radiansfiller_float_fb- Possibly lateral slip angle or other motion datasway- Vehicle sway motionheave- Vehicle heave motionsurge- Vehicle surge motion
Access motion data using the motion_data property:
telemetry = tc.telemetry
if telemetry and telemetry.motion_data:
motion = telemetry.motion_data
print(f"Sway: {motion['sway']:.3f}")
print(f"Heave: {motion['heave']:.3f}")
print(f"Surge: {motion['surge']:.3f}")
Heartbeat Type "~" (Extended Data)
Provides additional fields including:
throttle_filtered- Filtered throttle inputbrake_filtered- Filtered brake inputenergy_recovery- Energy recovery value- Additional unknown fields for future expansion
Access extended data using the extended_data property:
telemetry = tc.telemetry
if telemetry and telemetry.extended_data:
extended = telemetry.extended_data
print(f"Energy Recovery: {extended['energy_recovery']:.3f}")
print(f"Filtered Throttle: {extended['throttle_filtered']}")
Metadata
Release files for gt-telem 1.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| gt_telem-1.2.1.tar.gz | 71.7 kB | Without provenance | Details for gt_telem-1.2.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| gt_telem-1.2.1-py3-none-any.whl | Python 3 | none | any | Details for gt_telem-1.2.1-py3-none-any.whl |
Total release size: 131.2 kB
Release files / gt_telem-1.2.1.tar.gz
| Download URL | gt_telem-1.2.1.tar.gz |
|---|---|
| Size | 71.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b7496a9f6003c45b1db2433080c4f73a3dee536b09369396272a93d4c899bc54
|
|
BLAKE2b-256 checksum How to use checksums |
330fae5df3a25c6b4b878f56edf7056cc5eb3778bc94581b4731923f62370991
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.5
|
Release files / gt_telem-1.2.1-py3-none-any.whl
| Download URL | gt_telem-1.2.1-py3-none-any.whl |
|---|---|
| Size | 59.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
723bb3ab23d34543f81ab34f5e61552b8792775732580e4b3d0d069c257ef8ff
|
|
BLAKE2b-256 checksum How to use checksums |
bbfe4140b1668863dd8508617d812f2a0c50ee2d05ee83ddf55ce128ecab827e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.5
|
Security for gt-telem 1.2.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.