diff --git a/.gitignore b/.gitignore index 1104fc6..527dc4f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ misc/ -output/ \ No newline at end of file +output/ +telemetry.log \ No newline at end of file diff --git a/README.md b/README.md index 896718d..6b53b4b 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ - 📊 **Live Graphs**: Real-time charts for engine, suspension, input, etc. - 💾 **CSV Logging**: Save sessions to file for playback and later review. - ⏪ **Replay Mode**: Open saved CSV files to view logged data with graph control. -- 🔧 **User Controls**: Adjustable sample count, start/stop, open/clear logs, etc. +- 🔧 **User Controls**: Adjustable sample count, start/stop, open/clear logs, change IP/port, etc. ## 📷 Preview @@ -96,5 +96,4 @@ See [`LICENSE`](./LICENSE) for full details. - Torque conversion (not entirely accurate right now) - Fix for speed, suspension, and velocity charts (jittering at idle/standstill) -- Input to choose port? - UI Improvements \ No newline at end of file diff --git a/main.py b/main.py index b6ae5c5..e2b0f7e 100644 --- a/main.py +++ b/main.py @@ -45,10 +45,14 @@ QTabWidget, QLabel, QTextEdit, QLineEdit, QGridLayout, QSlider, QFileDialog ) from PySide6.QtCharts import QChart, QChartView, QLineSeries, QValueAxis -from PySide6.QtGui import QPainter +from PySide6.QtGui import QPainter, QIcon from struct import unpack import csv +# Defaults +tele_IP_addr = "0.0.0.0" +tele_port = 5607 + logging.basicConfig( level=logging.DEBUG, format="%(asctime)s [%(levelname)s] %(message)s", @@ -126,13 +130,13 @@ def to_dict(self): return {prop: getattr(self, prop) for prop in self.get_props()} class TelemetryReceiver(QObject): + global tele_IP_addr, tele_port data_received = Signal(dict) log_message = Signal(str) - def __init__(self, ip="0.0.0.0", port=5607): + + def __init__(self): super().__init__() - self.ip = ip - self.port = port self._running = False self.sock = None self.thread = None @@ -140,6 +144,8 @@ def __init__(self, ip="0.0.0.0", port=5607): def start(self): if self._running: return + self.ip = tele_IP_addr + self.port = tele_port self._running = True self.thread = threading.Thread(target=self._listen_loop, daemon=True) self.thread.start() @@ -248,8 +254,10 @@ def __init__(self): super().__init__() self.setWindowTitle("FH5 Telemetry") self.setStyleSheet("background-color: #121212; color: #808080;") + self.setWindowIcon(QIcon("./img/logo.ico")) + - self.receiver = TelemetryReceiver(ip="0.0.0.0", port=5607) + self.receiver = TelemetryReceiver() self.receiver.data_received.connect(self.buffer_data) self.receiver.log_message.connect(self.log) @@ -300,6 +308,22 @@ def __init__(self): controls.addStretch() + + # Ip / Port Changer + ip_input = QLabel("IP:Port") + ip_input.setAlignment(Qt.AlignLeft) + controls.addWidget(ip_input) + self.changeIP = QLineEdit("127.0.0.1:5500") + self.changeIP.setFixedWidth(100) + self.changeIP.setPlaceholderText("IP:Port") + controls.addWidget(self.changeIP) + + self.btn_changeIP = QPushButton("Apply") + self.btn_changeIP.clicked.connect(self.update_IP_port) + controls.addWidget(self.btn_changeIP) + + controls.addStretch() + self.btn_clear_logs = QPushButton("Clear Logs") self.btn_clear_logs.clicked.connect(self.log_panel.clear) controls.addWidget(self.btn_clear_logs) @@ -363,6 +387,9 @@ def _setup_charts(self): def buffer_data(self, data: dict): self.sample_count += 1 + # 4 decimal places had jitter in suspension data, 3 seems stable. + CALC_PRECISION = 3 + def scale_controls(val): return val * 100 / 255 def norm_steer(val): return val * 100 / 127 def to_mph(val): return val * 2.23694 @@ -386,6 +413,7 @@ def clamp_zero(val): return max(val, 0) for key, val in data.items(): if key in self.data_buffer and isinstance(val, (int, float)): + val = round(val, CALC_PRECISION) fixed_val = patch_map[key](val) if key in patch_map else val self.data_buffer[key].append(fixed_val) raw_snapshot[key] = fixed_val @@ -514,6 +542,24 @@ def stop(self): chart.data.clear() chart.add_values([]) + def update_IP_port(self, ): + global tele_IP_addr, tele_port + try: + ip_port = self.changeIP.text().split(":") + if len(ip_port) != 2: + raise ValueError("Invalid format. Use IP:Port") + print(f"IP port input: {ip_port}") + tele_IP_addr = ip_port[0] + tele_port = int(ip_port[1]) + log.info(f"Telemetry IP/Port changed to {tele_IP_addr}:{tele_port}") + self.log(f"Telemetry IP/Port changed to {tele_IP_addr}:{tele_port}") + if self.receiver._running: + self.receiver.stop() + self.receiver.start() + except Exception as e: + log.error(f"Failed to change IP/Port: {e}") + self.log(f"Failed to change IP/Port: {e}") + def toggle_logging(self, checked): if checked: self._start_logging() @@ -565,4 +611,4 @@ def closeEvent(self, event): app = QApplication(sys.argv) window = ForzaTelemetryApp() window.showMaximized() - sys.exit(app.exec()) \ No newline at end of file + sys.exit(app.exec())