From 66c9c5bcf0cb69038b7247bc7494c642fca770ec Mon Sep 17 00:00:00 2001 From: FrogAi <91348155+FrogAi@users.noreply.github.com> Date: Sun, 21 Jul 2024 19:07:03 -0700 Subject: [PATCH] FrogPilot features - Track FrogPilot drives --- selfdrive/controls/controlsd.py | 26 +++++ .../frogpilot/ui/qt/widgets/drive_stats.cc | 100 ++++++++++++++++++ .../frogpilot/ui/qt/widgets/drive_stats.h | 30 ++++++ selfdrive/ui/SConscript | 2 +- selfdrive/ui/qt/home.cc | 11 +- 5 files changed, 162 insertions(+), 7 deletions(-) create mode 100644 selfdrive/frogpilot/ui/qt/widgets/drive_stats.cc create mode 100644 selfdrive/frogpilot/ui/qt/widgets/drive_stats.h diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 85c9006ab..2bbe65062 100644 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -181,10 +181,19 @@ class Controls: # FrogPilot variables self.frogpilot_toggles = FrogPilotVariables.toggles + self.params_tracking = Params("/persist/tracking") + + self.total_drives = self.params_tracking.get_int("FrogPilotDrives") + self.total_kilometers = self.params_tracking.get_float("FrogPilotKilometers") + self.total_minutes = self.params_tracking.get_float("FrogPilotMinutes") + + self.drive_added = False self.openpilot_crashed_triggered = False self.update_toggles = False self.display_timer = 0 + self.drive_distance = 0 + self.drive_time = 0 def set_initial_state(self): if REPLAY: @@ -882,6 +891,23 @@ class Controls: self.openpilot_crashed_triggered = True def update_frogpilot_variables(self, CS): + self.drive_distance += CS.vEgo * DT_CTRL + self.drive_time += DT_CTRL + + if self.drive_time > 60 and CS.standstill: + self.total_kilometers += self.drive_distance / 1000 + self.params_tracking.put_float_nonblocking("FrogPilotKilometers", self.total_kilometers) + self.drive_distance = 0 + + self.total_minutes += self.drive_time / 60 + self.params_tracking.put_float_nonblocking("FrogPilotMinutes", self.total_minutes) + self.drive_time = 0 + + if not self.drive_added and self.sm.frame * DT_CTRL > 60 * 15: + self.total_drives += 1 + self.params_tracking.put_int_nonblocking("FrogPilotDrives", self.total_drives) + self.drive_added = True + FPCC = custom.FrogPilotCarControl.new_message() return FPCC diff --git a/selfdrive/frogpilot/ui/qt/widgets/drive_stats.cc b/selfdrive/frogpilot/ui/qt/widgets/drive_stats.cc new file mode 100644 index 000000000..6b6abee5f --- /dev/null +++ b/selfdrive/frogpilot/ui/qt/widgets/drive_stats.cc @@ -0,0 +1,100 @@ +#include "selfdrive/ui/qt/request_repeater.h" +#include "selfdrive/ui/qt/util.h" + +#include "selfdrive/frogpilot/ui/qt/widgets/drive_stats.h" + +static QLabel *newLabel(const QString &text, const QString &type) { + QLabel *label = new QLabel(text); + label->setProperty("type", type); + return label; +} + +DriveStats::DriveStats(QWidget *parent) : QFrame(parent) { + metric = params.getBool("IsMetric"); + + QVBoxLayout *main_layout = new QVBoxLayout(this); + main_layout->setContentsMargins(50, 25, 50, 20); + + auto add_stats_layouts = [=](const QString &title, StatsLabels &labels, bool FrogPilot=false) { + QGridLayout *grid_layout = new QGridLayout; + grid_layout->setVerticalSpacing(10); + grid_layout->setContentsMargins(0, 10, 0, 10); + + int row = 0; + grid_layout->addWidget(newLabel(title, FrogPilot ? "frogpilot_title" : "title"), row++, 0, 1, 3); + grid_layout->addItem(new QSpacerItem(0, 10), row++, 0, 1, 1); + + grid_layout->addWidget(labels.routes = newLabel("0", "number"), row, 0, Qt::AlignLeft); + grid_layout->addWidget(labels.distance = newLabel("0", "number"), row, 1, Qt::AlignLeft); + grid_layout->addWidget(labels.hours = newLabel("0", "number"), row, 2, Qt::AlignLeft); + + grid_layout->addWidget(newLabel((tr("Drives")), "unit"), row + 1, 0, Qt::AlignLeft); + grid_layout->addWidget(labels.distance_unit = newLabel(getDistanceUnit(), "unit"), row + 1, 1, Qt::AlignLeft); + grid_layout->addWidget(newLabel(tr("Hours"), "unit"), row + 1, 2, Qt::AlignLeft); + + main_layout->addLayout(grid_layout); + main_layout->addStretch(1); + }; + + add_stats_layouts(tr("ALL TIME"), all); + add_stats_layouts(tr("PAST WEEK"), week); + add_stats_layouts(tr("FROGPILOT"), frogPilot, true); + + if (auto dongleId = getDongleId()) { + QString url = CommaApi::BASE_URL + "/v1.1/devices/" + *dongleId + "/stats"; + RequestRepeater *repeater = new RequestRepeater(this, url, "ApiCache_DriveStats", 30); + QObject::connect(repeater, &RequestRepeater::requestDone, this, &DriveStats::parseResponse); + } + + setStyleSheet(R"( + DriveStats { + background-color: #333333; + border-radius: 10px; + } + + QLabel[type="title"] { font-size: 50px; font-weight: 500; } + QLabel[type="frogpilot_title"] { font-size: 50px; font-weight: 500; color: #178643; } + QLabel[type="number"] { font-size: 65px; font-weight: 400; } + QLabel[type="unit"] { font-size: 50px; font-weight: 300; color: #A0A0A0; } + )"); +} + +void DriveStats::updateStats() { + QJsonObject json = stats.object(); + + auto updateFrogPilot = [this](const QJsonObject &obj, StatsLabels &labels) { + labels.routes->setText(QString::number(paramsTracking.getInt("FrogPilotDrives"))); + labels.distance->setText(QString::number(int(paramsTracking.getFloat("FrogPilotKilometers") * (metric ? 1 : KM_TO_MILE)))); + labels.distance_unit->setText(getDistanceUnit()); + labels.hours->setText(QString::number(int(paramsTracking.getFloat("FrogPilotMinutes") / 60))); + }; + + updateFrogPilot(json["frogpilot"].toObject(), frogPilot); + + auto update = [=](const QJsonObject &obj, StatsLabels &labels) { + labels.routes->setText(QString::number((int)obj["routes"].toDouble())); + labels.distance->setText(QString::number(int(obj["distance"].toDouble() * (metric ? MILE_TO_KM : 1)))); + labels.distance_unit->setText(getDistanceUnit()); + labels.hours->setText(QString::number((int)(obj["minutes"].toDouble() / 60))); + }; + + update(json["all"].toObject(), all); + update(json["week"].toObject(), week); +} + +void DriveStats::parseResponse(const QString &response, bool success) { + if (!success) return; + + QJsonDocument doc = QJsonDocument::fromJson(response.trimmed().toUtf8()); + if (doc.isNull()) { + qDebug() << "JSON Parse failed on getting past drives statistics"; + return; + } + stats = doc; + updateStats(); +} + +void DriveStats::showEvent(QShowEvent *event) { + metric = params.getBool("IsMetric"); + updateStats(); +} diff --git a/selfdrive/frogpilot/ui/qt/widgets/drive_stats.h b/selfdrive/frogpilot/ui/qt/widgets/drive_stats.h new file mode 100644 index 000000000..d5bae3982 --- /dev/null +++ b/selfdrive/frogpilot/ui/qt/widgets/drive_stats.h @@ -0,0 +1,30 @@ +#pragma once + +#include "selfdrive/ui/ui.h" + +class DriveStats : public QFrame { + Q_OBJECT + +public: + explicit DriveStats(QWidget *parent = 0); + +private: + inline QString getDistanceUnit() const { return metric ? tr("KM") : tr("Miles"); } + + void showEvent(QShowEvent *event) override; + void updateStats(); + + Params params; + Params paramsTracking{"/persist/tracking"}; + + bool metric; + + QJsonDocument stats; + + struct StatsLabels { + QLabel *routes, *distance, *distance_unit, *hours; + } all, week, frogPilot; + +private slots: + void parseResponse(const QString &response, bool success); +}; diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript index 4d91f5468..be7e5c53c 100644 --- a/selfdrive/ui/SConscript +++ b/selfdrive/ui/SConscript @@ -23,7 +23,7 @@ widgets_src = ["ui.cc", "qt/widgets/input.cc", "qt/widgets/wifi.cc", "qt/widgets/offroad_alerts.cc", "qt/widgets/prime.cc", "qt/widgets/keyboard.cc", "qt/widgets/scrollview.cc", "qt/widgets/cameraview.cc", "#third_party/qrcode/QrCode.cc", "qt/request_repeater.cc", "qt/qt_window.cc", "qt/network/networking.cc", "qt/network/wifi_manager.cc", - "../frogpilot/ui/qt/widgets/frogpilot_controls.cc", + "../frogpilot/ui/qt/widgets/drive_stats.cc", "../frogpilot/ui/qt/widgets/frogpilot_controls.cc", "../frogpilot/navigation/ui/navigation_settings.cc", "../frogpilot/ui/qt/offroad/control_settings.cc", "../frogpilot/ui/qt/offroad/vehicle_settings.cc", "../frogpilot/ui/qt/offroad/visual_settings.cc"] diff --git a/selfdrive/ui/qt/home.cc b/selfdrive/ui/qt/home.cc index fb2983948..08dfc772b 100644 --- a/selfdrive/ui/qt/home.cc +++ b/selfdrive/ui/qt/home.cc @@ -13,6 +13,8 @@ #include "selfdrive/ui/qt/maps/map_settings.h" #endif +#include "selfdrive/frogpilot/ui/qt/widgets/drive_stats.h" + // HomeWindow: the container for the offroad and onroad UIs HomeWindow::HomeWindow(QWidget* parent) : QWidget(parent) { @@ -162,20 +164,17 @@ OffroadHome::OffroadHome(QWidget* parent) : QFrame(parent) { home_layout->setContentsMargins(0, 0, 0, 0); home_layout->setSpacing(30); - // left: MapSettings/PrimeAdWidget + // left: MapSettings QStackedWidget *left_widget = new QStackedWidget(this); #ifdef ENABLE_MAPS left_widget->addWidget(new MapSettings); #else left_widget->addWidget(new QWidget); #endif - left_widget->addWidget(new PrimeAdWidget); + left_widget->addWidget(new DriveStats); left_widget->setStyleSheet("border-radius: 10px;"); - left_widget->setCurrentIndex(uiState()->hasPrime() ? 0 : 1); - connect(uiState(), &UIState::primeChanged, [=](bool prime) { - left_widget->setCurrentIndex(prime ? 0 : 1); - }); + left_widget->setCurrentIndex(1); home_layout->addWidget(left_widget, 1);