From f0444110c9d6b5a7d8e40f65b3b0c2ab3278e711 Mon Sep 17 00:00:00 2001 From: James <91348155+FrogAi@users.noreply.github.com> Date: Mon, 1 Dec 2025 12:00:00 -0700 Subject: [PATCH] Sidebar Metrics --- selfdrive/ui/qt/sidebar.cc | 122 ++++++++++++++++++++++++++++++----- selfdrive/ui/qt/sidebar.h | 4 ++ system/hardware/hardwared.py | 5 +- system/loggerd/config.py | 10 +++ 4 files changed, 125 insertions(+), 16 deletions(-) diff --git a/selfdrive/ui/qt/sidebar.cc b/selfdrive/ui/qt/sidebar.cc index 1ab2fbb5..92b5d5d5 100644 --- a/selfdrive/ui/qt/sidebar.cc +++ b/selfdrive/ui/qt/sidebar.cc @@ -47,19 +47,47 @@ Sidebar::Sidebar(QWidget *parent) : QFrame(parent), onroad(false), flag_pressed( void Sidebar::mousePressEvent(QMouseEvent *event) { // FrogPilot variables + QPoint pos = event->pos(); + + static constexpr QRect cpuRect = {30, 496, 240, 126}; + static constexpr QRect memoryRect = {30, 654, 240, 126}; + static constexpr QRect tempRect = {30, 338, 240, 126}; + + static int showChip = 0; + static int showMemory = 0; + static int showTemp = 0; + FrogPilotUIState *fs = frogpilotUIState(); FrogPilotUIScene &frogpilot_scene = fs->frogpilot_scene; QJsonObject &frogpilot_toggles = frogpilot_scene.frogpilot_toggles; - if (onroad && home_btn.contains(event->pos())) { + if (cpuRect.contains(pos) && frogpilot_toggles.value("developer_ui").toBool()) { + showChip = (showChip + 1) % 3; + + params.putBool("ShowCPU", showChip == 1); + params.putBool("ShowGPU", showChip == 2); + } else if (memoryRect.contains(pos) && frogpilot_toggles.value("developer_ui").toBool()) { + showMemory = (showMemory + 1) % 4; + + params.putBool("ShowMemoryUsage", showMemory == 1); + params.putBool("ShowStorageLeft", showMemory == 2); + params.putBool("ShowStorageUsed", showMemory == 3); + } else if (tempRect.contains(pos) && frogpilot_toggles.value("developer_ui").toBool()) { + showTemp = (showTemp + 1) % 3; + + params.putBool("Fahrenheit", showTemp == 2); + params.putBool("NumericalTemp", showTemp != 0); + } else if (onroad && home_btn.contains(pos)) { flag_pressed = true; - update(); - } else if (settings_btn.contains(event->pos())) { + } else if (settings_btn.contains(pos)) { settings_pressed = true; - update(); } else if (recording_audio && mic_indicator_btn.contains(event->pos())) { mic_indicator_pressed = true; + } + + if (!(flag_pressed || mic_indicator_pressed || settings_pressed)) { update(); + updateFrogPilotToggles(); } } @@ -115,12 +143,14 @@ void Sidebar::updateState(const UIState &s, const FrogPilotUIState &fs) { } setProperty("connectStatus", QVariant::fromValue(connectStatus)); - ItemStatus tempStatus = {{tr("TEMP"), tr("HIGH")}, danger_color}; + int maxTempC = deviceState.getMaxTempC(); + QString max_temp = frogpilot_toggles.value("fahrenheit").toBool() ? QString::number(maxTempC * 9 / 5 + 32) + "°F" : QString::number(maxTempC) + "°C"; + ItemStatus tempStatus = {{tr("TEMP"), frogpilot_toggles.value("numerical_temp").toBool() ? max_temp : tr("HIGH")}, danger_color}; auto ts = deviceState.getThermalStatus(); if (ts == cereal::DeviceState::ThermalStatus::GREEN) { - tempStatus = {{tr("TEMP"), tr("GOOD")}, QColor(frogpilot_toggles.value("sidebar_color1").toString())}; + tempStatus = {{tr("TEMP"), frogpilot_toggles.value("numerical_temp").toBool() ? max_temp : tr("GOOD")}, QColor(frogpilot_toggles.value("sidebar_color1").toString())}; } else if (ts == cereal::DeviceState::ThermalStatus::YELLOW) { - tempStatus = {{tr("TEMP"), tr("OK")}, warning_color}; + tempStatus = {{tr("TEMP"), frogpilot_toggles.value("numerical_temp").toBool() ? max_temp : tr("OK")}, warning_color}; } setProperty("tempStatus", QVariant::fromValue(tempStatus)); @@ -133,6 +163,50 @@ void Sidebar::updateState(const UIState &s, const FrogPilotUIState &fs) { setProperty("recordingAudio", s.scene.recording_audio); // FrogPilot variables + if (frogpilot_toggles.value("cpu_metrics").toBool() || frogpilot_toggles.value("gpu_metrics").toBool()) { + capnp::List::Reader cpu_loads = deviceState.getCpuUsagePercent(); + int cpu_usage = cpu_loads.size() != 0 ? std::accumulate(cpu_loads.begin(), cpu_loads.end(), 0) / cpu_loads.size() : 0; + int gpu_usage = deviceState.getGpuUsagePercent(); + int usage = frogpilot_toggles.value("cpu_metrics").toBool() ? cpu_usage : gpu_usage; + + QString chip_usage = QString::number(usage) + "%"; + + ItemStatus chipStatus = {{frogpilot_toggles.value("gpu_metrics").toBool() ? tr("GPU") : tr("CPU"), chip_usage}, QColor(frogpilot_toggles.value("sidebar_color2").toString())}; + if (usage >= 85) { + chipStatus = {{frogpilot_toggles.value("gpu_metrics").toBool() ? tr("GPU") : tr("CPU"), chip_usage}, danger_color}; + } else if (usage >= 70) { + chipStatus = {{frogpilot_toggles.value("gpu_metrics").toBool() ? tr("GPU") : tr("CPU"), chip_usage}, warning_color}; + } + setProperty("chipStatus", QVariant::fromValue(chipStatus)); + } + + if (frogpilot_toggles.value("memory_metrics").toBool() || frogpilot_toggles.value("storage_left_metrics").toBool() || frogpilot_toggles.value("storage_used_metrics").toBool()) { + int free_space = deviceState.getFreeSpacePercent(); + int memory_usage = deviceState.getMemoryUsagePercent(); + int storage_left = frogpilotDeviceState.getFreeSpace(); + int storage_used = frogpilotDeviceState.getUsedSpace(); + + QString memory = QString::number(memory_usage) + "%"; + QString storage = QString::number(frogpilot_toggles.value("storage_left_metrics").toBool() ? storage_left : storage_used) + tr(" GB"); + + if (frogpilot_toggles.value("memory_metrics").toBool()) { + ItemStatus memoryStatus = {{tr("MEMORY"), memory}, QColor(frogpilot_toggles.value("sidebar_color3").toString())}; + if (memory_usage >= 85) { + memoryStatus = {{tr("MEMORY"), memory}, danger_color}; + } else if (memory_usage >= 70) { + memoryStatus = {{tr("MEMORY"), memory}, warning_color}; + } + setProperty("memoryStatus", QVariant::fromValue(memoryStatus)); + } else { + ItemStatus storageStatus = {{frogpilot_toggles.value("storage_left_metrics").toBool() ? tr("LEFT") : tr("USED"), storage}, QColor(frogpilot_toggles.value("sidebar_color3").toString())}; + if (free_space < 25 && free_space >= 10) { + storageStatus = {{frogpilot_toggles.value("storage_left_metrics").toBool() ? tr("LEFT") : tr("USED"), storage}, warning_color}; + } else if (10 > free_space) { + storageStatus = {{frogpilot_toggles.value("storage_left_metrics").toBool() ? tr("LEFT") : tr("USED"), storage}, danger_color}; + } + setProperty("storageStatus", QVariant::fromValue(storageStatus)); + } + } } void Sidebar::paintEvent(QPaintEvent *event) { @@ -163,12 +237,20 @@ void Sidebar::paintEvent(QPaintEvent *event) { QJsonObject &frogpilot_toggles = frogpilot_scene.frogpilot_toggles; // network - int x = 58; - const QColor gray(0x54, 0x54, 0x54); - for (int i = 0; i < 5; ++i) { - p.setBrush(i < net_strength ? Qt::white : gray); - p.drawEllipse(x, 196, 27, 27); - x += 37; + if (frogpilot_toggles.value("ip_metrics").toBool()) { + p.setPen(QColor(0xff, 0xff, 0xff)); + p.save(); + p.setFont(InterFont(30)); + p.drawText(QRect(50, 196, 225, 27), Qt::AlignLeft | Qt::AlignVCenter, frogpilotUIState()->wifi->getIp4Address()); + p.restore(); + } else { + int x = 58; + const QColor gray(0x54, 0x54, 0x54); + for (int i = 0; i < 5; ++i) { + p.setBrush(i < net_strength ? Qt::white : gray); + p.drawEllipse(x, 196, 27, 27); + x += 37; + } } p.setFont(InterFont(35)); @@ -183,8 +265,18 @@ void Sidebar::paintEvent(QPaintEvent *event) { // metrics drawMetric(p, temp_status.first, temp_status.second, 338); - drawMetric(p, panda_status.first, panda_status.second, 496); - drawMetric(p, connect_status.first, connect_status.second, 654); + if (frogpilot_toggles.value("cpu_metrics").toBool() || frogpilot_toggles.value("gpu_metrics").toBool()) { + drawMetric(p, chip_status.first, chip_status.second, 496); + } else { + drawMetric(p, panda_status.first, panda_status.second, 496); + } + if (frogpilot_toggles.value("memory_metrics").toBool()) { + drawMetric(p, memory_status.first, memory_status.second, 654); + } else if (frogpilot_toggles.value("storage_left_metrics").toBool() || frogpilot_toggles.value("storage_used_metrics").toBool()) { + drawMetric(p, storage_status.first, storage_status.second, 654); + } else { + drawMetric(p, connect_status.first, connect_status.second, 654); + } } // FrogPilot variables diff --git a/selfdrive/ui/qt/sidebar.h b/selfdrive/ui/qt/sidebar.h index ae442782..770cf15b 100644 --- a/selfdrive/ui/qt/sidebar.h +++ b/selfdrive/ui/qt/sidebar.h @@ -21,6 +21,9 @@ class Sidebar : public QFrame { Q_PROPERTY(bool recordingAudio MEMBER recording_audio NOTIFY valueChanged); // FrogPilot properties + Q_PROPERTY(ItemStatus chipStatus MEMBER chip_status NOTIFY valueChanged) + Q_PROPERTY(ItemStatus memoryStatus MEMBER memory_status NOTIFY valueChanged) + Q_PROPERTY(ItemStatus storageStatus MEMBER storage_status NOTIFY valueChanged) public: explicit Sidebar(QWidget* parent = 0); @@ -63,6 +66,7 @@ protected: int net_strength = 0; // FrogPilot variables + ItemStatus chip_status, memory_status, storage_status; private: std::unique_ptr pm; diff --git a/system/hardware/hardwared.py b/system/hardware/hardwared.py index b2d6a58a..7c5cf1f4 100644 --- a/system/hardware/hardwared.py +++ b/system/hardware/hardwared.py @@ -18,7 +18,7 @@ from openpilot.common.params import Params from openpilot.common.realtime import DT_HW from openpilot.selfdrive.selfdrived.alertmanager import set_offroad_alert from openpilot.system.hardware import HARDWARE, TICI, AGNOS, PC -from openpilot.system.loggerd.config import get_available_percent +from openpilot.system.loggerd.config import get_available_bytes, get_available_percent, get_used_bytes from openpilot.system.statsd import statlog from openpilot.common.swaglog import cloudlog from openpilot.system.hardware.power_monitoring import PowerMonitoring @@ -429,6 +429,9 @@ def hardware_thread(end_event, hw_queue) -> None: # FrogPilot variables fpmsg = messaging.new_message('frogpilotDeviceState') + fpmsg.frogpilotDeviceState.freeSpace = round(get_available_bytes(default=32.0 * (2 ** 30)) / (2 ** 30)) + fpmsg.frogpilotDeviceState.usedSpace = round(get_used_bytes(default=0.0) / (2 ** 30)) + pm.send("frogpilotDeviceState", fpmsg) # Log to statsd diff --git a/system/loggerd/config.py b/system/loggerd/config.py index ece38d0c..bd25cd31 100644 --- a/system/loggerd/config.py +++ b/system/loggerd/config.py @@ -30,3 +30,13 @@ def get_available_bytes(default: int) -> int: # FrogPilot variables +def get_used_bytes(default: int) -> int: + try: + statvfs = os.statvfs(Paths.log_root()) + total_bytes = statvfs.f_blocks * statvfs.f_frsize + available_bytes = get_available_bytes(default) + used_bytes = total_bytes - available_bytes + except OSError: + used_bytes = default + + return used_bytes