Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Tests

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
test:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Install uv
uses: astral-sh/setup-uv@v5
with:
enable-cache: true

- name: Set up Python
run: uv python install

- name: Install dependencies
run: uv sync --dev

- name: Run tests
run: uv run pytest
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# F1 25 Real-Time Telemetry Plotter

[![Tests](https://github.com/sully90/telemetry/actions/workflows/test.yml/badge.svg)](https://github.com/sully90/telemetry/actions)
![Python Version](https://img.shields.io/badge/python-3.12+-blue.svg)

A Python-based real-time telemetry plotter for F1 25. It provides high-frequency visualization of speed, pedal inputs, and racing lines across dual windows, optimized for multi-monitor setups.

![Example Screenshot](screenshot_20260406_133551.png)
Expand Down
9 changes: 9 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@ dependencies = [
telemetry = "telemetry.__main__:main"
telemetry-playback = "telemetry.playback:main"

[tool.pytest.ini_options]
testpaths = ["tests"]
pythonpath = ["src"]

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[dependency-groups]
dev = [
"pytest>=9.0.3",
]
63 changes: 63 additions & 0 deletions tests/test_data_manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import pytest
from unittest.mock import MagicMock
from telemetry.data_manager import TelemetryData

@pytest.fixture
def telemetry_data():
# Mock TelemetryRecorder to avoid file IO
data = TelemetryData()
data.recorder = MagicMock()
return data

def test_initialization(telemetry_data):
assert telemetry_data.player_idx == 0
assert telemetry_data.track_name == "F1 25 Session"
assert len(telemetry_data.all_cars_data) == 22
assert telemetry_data.current_lap_num == -1

def test_update_session(telemetry_data):
telemetry_data.update_session(0, 15, 1) # Melbourne, Race, Player 1
assert telemetry_data.track_name == "Melbourne"
assert telemetry_data.session_type == 15
assert telemetry_data.player_idx == 1
assert telemetry_data.current_lap_data == telemetry_data.all_cars_data[1]

def test_update_motion_speed_calculation(telemetry_data):
car_idx = 0
# First update to set initial position
telemetry_data.update_motion(car_idx, 0, 0, 0, 0, 0, 0, 10.0, 1)

# Second update 1 second later, 10 meters away
# speed = 10 m / 1 s = 10 m/s = 22.3694 mph
telemetry_data.update_motion(car_idx, 10, 0, 0, 0, 0, 0, 11.0, 2)

latch = telemetry_data.car_latches[car_idx]
assert pytest.approx(latch["speed_mph"], 0.0001) == 22.3694

def test_lap_completion(telemetry_data):
telemetry_data.update_session(0, 10, 0) # Melbourne, TT, Player 0
car_idx = 0

# Simulate some data points for a lap
for i in range(1, 103):
telemetry_data.update_lap(car_idx, 1, float(i), i * 1000, float(i), i)
telemetry_data.update_motion(car_idx, i, 0, 0, 0, 0, 0, float(i) + 0.1, i+1)

# Complete the lap
telemetry_data.update_lap(car_idx, 2, 0.0, 103000, 103.0, 103)

# Check if history is updated
assert len(telemetry_data.car_histories[car_idx]) == 1
assert telemetry_data.best_lap_time != float('inf')
assert telemetry_data.current_lap_num == 2

def test_flashback_reset(telemetry_data):
car_idx = 0
telemetry_data.update_lap(car_idx, 2, 1000.0, 50000, 50.0, 50)
telemetry_data.update_motion(car_idx, 100, 0, 0, 0, 0, 0, 50.0, 50)
assert len(telemetry_data.all_cars_data[car_idx]["distance"]) > 0

# Simulate flashback (lap number decreases or distance jumps back)
telemetry_data.update_lap(car_idx, 1, 500.0, 25000, 60.0, 60)

assert len(telemetry_data.all_cars_data[car_idx]["distance"]) == 0
34 changes: 34 additions & 0 deletions tests/test_recorder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import os
import pytest
import pandas as pd
from telemetry.recorder import TelemetryRecorder

def test_recorder_flow(tmp_path):
# Use a temporary directory for recordings
recorder = TelemetryRecorder(output_dir=str(tmp_path))

# Mock data
track_name = "Melbourne"
units = {"speed": "mph"}

recorder.start_recording(track_name, units)
assert recorder.is_recording

sample = {
"car_idx": 0,
"distance": 10.5,
"speed": 150.0
}
recorder.add_sample(sample)
assert len(recorder.recording_log) == 1

filepath = recorder.stop_recording()
assert not recorder.is_recording
assert os.path.exists(filepath)
assert filepath.endswith(".parquet")

# Verify data can be read back
df = recorder.read_recording(filepath)
assert len(df) == 1
assert df.iloc[0]["car_idx"] == 0
assert df.iloc[0]["distance"] == 10.5
60 changes: 60 additions & 0 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading