Device Management

Added toggles to customize the device shut down time, disable logging, disable uploads, disable internet connection check, and set a custom battery threshold check to help prevent battery drain.
This commit is contained in:
FrogAi
2024-04-03 13:18:38 -07:00
parent ecfbaebfea
commit 5b5e7fa3b5
14 changed files with 144 additions and 13 deletions
+7
View File
@@ -247,6 +247,8 @@ std::unordered_map<std::string, uint32_t> keys = {
{"CustomTheme", PERSISTENT},
{"CydiaTune", PERSISTENT},
{"DecelerationProfile", PERSISTENT},
{"DeviceManagement", PERSISTENT},
{"DeviceShutdown", PERSISTENT},
{"DisengageVolume", PERSISTENT},
{"DynamicPathWidth", PERSISTENT},
{"EngageVolume", PERSISTENT},
@@ -256,11 +258,16 @@ std::unordered_map<std::string, uint32_t> keys = {
{"HideAOLStatusBar", PERSISTENT},
{"HideCEMStatusBar", PERSISTENT},
{"HideLeadMarker", PERSISTENT},
{"IncreaseThermalLimits", PERSISTENT},
{"LaneLinesWidth", PERSISTENT},
{"LateralTune", PERSISTENT},
{"LongitudinalTune", PERSISTENT},
{"LowVoltageShutdown", PERSISTENT},
{"ManualUpdateInitiated", PERSISTENT},
{"ModelUI", PERSISTENT},
{"NoLogging", PERSISTENT},
{"NoUploads", PERSISTENT},
{"OfflineMode", PERSISTENT},
{"PathEdgeWidth", PERSISTENT},
{"PathWidth", PERSISTENT},
{"PauseAOLOnBrake", PERSISTENT},
+5 -1
View File
@@ -245,7 +245,8 @@ class Controls:
# Create events for temperature, disk space, and memory
if self.sm['deviceState'].thermalStatus >= ThermalStatus.red:
self.events.add(EventName.overheat)
if not self.increase_thermal_limits or self.sm['deviceState'].thermalStatus == ThermalStatus.danger:
self.events.add(EventName.overheat)
if self.sm['deviceState'].freeSpacePercent < 7 and not SIMULATION:
# under 7% of space free no enable allowed
self.events.add(EventName.outOfSpace)
@@ -922,6 +923,9 @@ class Controls:
frog_sounds = custom_sounds == 1
self.goat_scream = frog_sounds and self.params.get_bool("GoatScream")
device_management = self.params.get_bool("DeviceManagement")
self.increase_thermal_limits = device_management and self.params.get_bool("IncreaseThermalLimits")
lateral_tune = self.params.get_bool("LateralTune")
longitudinal_tune = self.CP.openpilotLongitudinalControl and self.params.get_bool("LongitudinalTune")
@@ -0,0 +1,6 @@
<svg width="68" height="68" viewBox="0 0 68 68" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M34.0004 8.63599C21.8284 8.63599 10.7444 13.26 2.31243 20.808C1.56443 21.488 1.4964 22.644 2.1084 23.392L4.76041 26.452C5.44041 27.2 6.59641 27.268 7.34441 26.588C14.4164 20.196 23.7324 16.32 33.9324 16.32C44.1324 16.32 53.4484 20.196 60.5204 26.588C61.2684 27.268 62.4244 27.2 63.1044 26.452L65.7564 23.392C66.4364 22.644 66.3004 21.488 65.5524 20.808C57.2564 13.26 46.1724 8.63599 34.0004 8.63599Z" fill="#FF0000"/>
<path d="M34.0004 22.032C25.1604 22.032 17.0684 25.432 11.0164 30.94C10.2684 31.62 10.2004 32.708 10.8804 33.456L13.3964 36.38C14.0764 37.196 15.2324 37.196 16.0484 36.516C20.8084 32.164 27.1324 29.512 34.0684 29.512C41.0044 29.512 47.3284 32.164 52.0884 36.516C52.8364 37.196 54.0604 37.196 54.7404 36.38L57.2564 33.456C57.8684 32.708 57.8684 31.552 57.1204 30.94C50.9324 25.364 42.8404 22.032 34.0004 22.032Z" fill="#FF0000"/>
<path d="M34.0007 35.36C28.4247 35.36 23.3927 37.536 19.6527 41.14C18.9727 41.82 18.9047 42.908 19.5847 43.656L21.9647 46.444C22.6447 47.26 23.8687 47.26 24.6167 46.58C27.0647 44.2 30.3287 42.772 34.0007 42.772C37.6727 42.772 40.9367 44.2 43.3847 46.58C44.1327 47.328 45.3567 47.26 46.0367 46.444L48.4167 43.656C49.0287 42.908 49.0287 41.82 48.3487 41.14C44.6087 37.536 39.5767 35.36 34.0007 35.36Z" fill="#FF0000"/>
<path d="M34.0005 48.688C31.7565 48.688 29.7165 49.708 28.3565 51.34C27.7445 52.02 27.7445 53.04 28.3565 53.72L32.6405 58.684C33.3885 59.5 34.6804 59.5 35.4284 58.684L39.7125 53.72C40.3245 53.04 40.3245 52.02 39.7125 51.34C38.2845 49.708 36.2445 48.688 34.0005 48.688Z" fill="#FF0000"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

@@ -20,6 +20,14 @@ FrogPilotControlsPanel::FrogPilotControlsPanel(SettingsWindow *parent) : FrogPil
{"CustomPersonalities", tr("Custom Driving Personalities"), tr("Customize the driving personality profiles to your driving style."), "../frogpilot/assets/toggle_icons/icon_custom.png"},
{"DeviceManagement", tr("Device Management"), tr("Tweak your device's behaviors to your personal preferences."), "../frogpilot/assets/toggle_icons/icon_device.png"},
{"DeviceShutdown", tr("Device Shutdown Timer"), tr("Configure how quickly the device shuts down after going offroad."), ""},
{"NoLogging", tr("Disable Logging"), tr("Turn off all data tracking to enhance privacy or reduce thermal load."), ""},
{"NoUploads", tr("Disable Uploads"), tr("Turn off all data uploads to comma's servers."), ""},
{"IncreaseThermalLimits", tr("Increase Thermal Safety Limit"), tr("Allow the device to run at a temperature above comma's recommended thermal limits."), ""},
{"LowVoltageShutdown", tr("Low Voltage Shutdown Threshold"), tr("Automatically shut the device down when your battery reaches a specific voltage level to prevent killing your battery."), ""},
{"OfflineMode", tr("Offline Mode"), tr("Allow the device to be offline indefinitely."), ""},
{"LateralTune", tr("Lateral Tuning"), tr("Modify openpilot's steering behavior."), "../frogpilot/assets/toggle_icons/icon_lateral_tune.png"},
{"LongitudinalTune", tr("Longitudinal Tuning"), tr("Modify openpilot's acceleration and braking behavior."), "../frogpilot/assets/toggle_icons/icon_longitudinal_tune.png"},
@@ -135,6 +143,24 @@ FrogPilotControlsPanel::FrogPilotControlsPanel(SettingsWindow *parent) : FrogPil
relaxedProfile = new FrogPilotDualParamControl(relaxedFollow, relaxedJerk, this, true);
addItem(relaxedProfile);
} else if (param == "DeviceManagement") {
FrogPilotParamManageControl *deviceManagementToggle = new FrogPilotParamManageControl(param, title, desc, icon, this);
QObject::connect(deviceManagementToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() {
openParentToggle();
for (auto &[key, toggle] : toggles) {
toggle->setVisible(deviceManagementKeys.find(key.c_str()) != deviceManagementKeys.end());
}
});
toggle = deviceManagementToggle;
} else if (param == "DeviceShutdown") {
std::map<int, QString> shutdownLabels;
for (int i = 0; i <= 33; ++i) {
shutdownLabels[i] = i == 0 ? tr("5 mins") : i <= 3 ? QString::number(i * 15) + tr(" mins") : QString::number(i - 3) + (i == 4 ? tr(" hour") : tr(" hours"));
}
toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 33, shutdownLabels, this, false);
} else if (param == "LowVoltageShutdown") {
toggle = new FrogPilotParamValueControl(param, title, desc, icon, 11.8, 12.5, std::map<int, QString>(), this, false, tr(" volts"), 1, 0.01);
} else if (param == "LateralTune") {
FrogPilotParamManageControl *lateralTuneToggle = new FrogPilotParamManageControl(param, title, desc, icon, this);
QObject::connect(lateralTuneToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() {
@@ -218,6 +244,30 @@ FrogPilotControlsPanel::FrogPilotControlsPanel(SettingsWindow *parent) : FrogPil
}
});
QObject::connect(toggles["IncreaseThermalLimits"], &ToggleControl::toggleFlipped, [this]() {
if (params.getBool("IncreaseThermalLimits")) {
FrogPilotConfirmationDialog::toggleAlert(
tr("WARNING: This can cause premature wear or damage by running the device over comma's recommended temperature limits!"),
tr("I understand the risks."), this);
}
});
QObject::connect(toggles["NoLogging"], &ToggleControl::toggleFlipped, [this]() {
if (params.getBool("NoLogging")) {
FrogPilotConfirmationDialog::toggleAlert(
tr("WARNING: This will prevent your drives from being recorded and the data will be unobtainable!"),
tr("I understand the risks."), this);
}
});
QObject::connect(toggles["NoUploads"], &ToggleControl::toggleFlipped, [this]() {
if (params.getBool("NoUploads")) {
FrogPilotConfirmationDialog::toggleAlert(
tr("WARNING: This will prevent your drives from appearing on comma connect which may impact debugging and support!"),
tr("I understand the risks."), this);
}
});
std::set<QString> rebootKeys = {"AlwaysOnLateral", "AlwaysOnLateralMain"};
for (const QString &key : rebootKeys) {
QObject::connect(toggles[key.toStdString().c_str()], &ToggleControl::toggleFlipped, [this]() {
@@ -33,7 +33,7 @@ private:
std::set<QString> aolKeys = {"AlwaysOnLateralMain", "HideAOLStatusBar", "PauseAOLOnBrake"};
std::set<QString> conditionalExperimentalKeys = {"CECurves", "CECurvesLead", "CENavigation", "CESignal", "CESlowerLead", "CEStopLights", "HideCEMStatusBar"};
std::set<QString> deviceManagementKeys = {};
std::set<QString> deviceManagementKeys = {"DeviceShutdown", "IncreaseThermalLimits", "LowVoltageShutdown", "NoLogging", "NoUploads", "OfflineMode"};
std::set<QString> experimentalModeActivationKeys = {};
std::set<QString> laneChangeKeys = {};
std::set<QString> lateralTuneKeys = {};
+14 -7
View File
@@ -42,21 +42,28 @@ def only_offroad(started, params, CP: car.CarParams) -> bool:
return not started
# FrogPilot functions
def allow_logging(started, params, CP: car.CarParams) -> bool:
allow_logging = not (params.get_bool("DeviceManagement") and params.get_bool("NoLogging"))
return allow_logging and logging(started, params, CP)
def allow_uploads(started, params, CP: car.CarParams) -> bool:
allow_uploads = not (params.get_bool("DeviceManagement") and params.get_bool("NoUploads"))
return allow_uploads
procs = [
DaemonProcess("manage_athenad", "selfdrive.athena.manage_athenad", "AthenadPid"),
NativeProcess("camerad", "system/camerad", ["./camerad"], driverview),
NativeProcess("logcatd", "system/logcatd", ["./logcatd"], only_onroad),
NativeProcess("proclogd", "system/proclogd", ["./proclogd"], only_onroad),
PythonProcess("logmessaged", "system.logmessaged", always_run),
NativeProcess("logcatd", "system/logcatd", ["./logcatd"], allow_logging),
NativeProcess("proclogd", "system/proclogd", ["./proclogd"], allow_logging),
PythonProcess("logmessaged", "system.logmessaged", allow_logging),
PythonProcess("micd", "system.micd", iscar),
PythonProcess("timed", "system.timed", always_run, enabled=not PC),
PythonProcess("dmonitoringmodeld", "selfdrive.modeld.dmonitoringmodeld", driverview, enabled=(not PC or WEBCAM)),
NativeProcess("encoderd", "system/loggerd", ["./encoderd"], only_onroad),
NativeProcess("encoderd", "system/loggerd", ["./encoderd"], allow_logging),
NativeProcess("stream_encoderd", "system/loggerd", ["./encoderd", "--stream"], notcar),
NativeProcess("loggerd", "system/loggerd", ["./loggerd"], logging),
NativeProcess("loggerd", "system/loggerd", ["./loggerd"], allow_logging),
NativeProcess("modeld", "selfdrive/modeld", ["./modeld"], only_onroad),
NativeProcess("mapsd", "selfdrive/navd", ["./mapsd"], only_onroad),
PythonProcess("navmodeld", "selfdrive.modeld.navmodeld", only_onroad),
@@ -82,8 +89,8 @@ procs = [
PythonProcess("thermald", "selfdrive.thermald.thermald", always_run),
PythonProcess("tombstoned", "selfdrive.tombstoned", always_run, enabled=not PC),
PythonProcess("updated", "selfdrive.updated.updated", only_offroad, enabled=not PC),
PythonProcess("uploader", "system.loggerd.uploader", always_run),
PythonProcess("statsd", "selfdrive.statsd", always_run),
PythonProcess("uploader", "system.loggerd.uploader", allow_uploads),
PythonProcess("statsd", "selfdrive.statsd", allow_logging),
# debug procs
NativeProcess("bridge", "cereal/messaging", ["./bridge"], notcar),
+7 -2
View File
@@ -37,6 +37,11 @@ class PowerMonitoring:
self.car_battery_capacity_uWh = max((CAR_BATTERY_CAPACITY_uWh / 10), int(car_battery_capacity_uWh))
# FrogPilot variables
device_management = self.params.get_bool("DeviceManagement")
device_shutdown_setting = self.params.get_int("DeviceShutdown") if device_management else 33
# If the toggle is set for < 1 hour, configure by 15 minute increments
self.device_shutdown_time = (device_shutdown_setting - 3) * 3600 if device_shutdown_setting >= 4 else device_shutdown_setting * (60 * 15)
self.low_voltage_shutdown = self.params.get_float("LowVoltageShutdown") if device_management else VBATT_PAUSE_CHARGING
# Calculation tick
def calculate(self, voltage: int | None, ignition: bool):
@@ -116,9 +121,9 @@ class PowerMonitoring:
now = time.monotonic()
should_shutdown = False
offroad_time = (now - offroad_timestamp)
low_voltage_shutdown = (self.car_voltage_mV < (VBATT_PAUSE_CHARGING * 1e3) and
low_voltage_shutdown = (self.car_voltage_mV < (self.low_voltage_shutdown * 1e3) and
offroad_time > VOLTAGE_SHUTDOWN_MIN_OFFROAD_TIME_S)
should_shutdown |= offroad_time > MAX_TIME_OFFROAD_S
should_shutdown |= offroad_time > self.device_shutdown_time
should_shutdown |= low_voltage_shutdown
should_shutdown |= (self.car_battery_capacity_uWh <= 0)
should_shutdown &= not ignition
+5 -1
View File
@@ -204,6 +204,10 @@ def thermald_thread(end_event, hw_queue) -> None:
fan_controller = None
# FrogPilot variables
device_management = params.get_bool("DeviceManagement")
offline_mode = device_management and params.get_bool("OfflineMode")
while not end_event.is_set():
sm.update(PANDA_STATES_TIMEOUT)
@@ -296,7 +300,7 @@ def thermald_thread(end_event, hw_queue) -> None:
# **** starting logic ****
startup_conditions["up_to_date"] = params.get("Offroad_ConnectivityNeeded") is None or params.get_bool("DisableUpdates") or params.get_bool("SnoozeUpdate")
startup_conditions["up_to_date"] = params.get("Offroad_ConnectivityNeeded") is None or params.get_bool("DisableUpdates") or params.get_bool("SnoozeUpdate") or offline_mode
startup_conditions["not_uninstalling"] = not params.get_bool("DoUninstall")
startup_conditions["accepted_terms"] = params.get("HasAcceptedTerms") == terms_version
+2
View File
@@ -158,6 +158,8 @@ void TogglesPanel::showEvent(QShowEvent *event) {
void TogglesPanel::updateToggles() {
auto disengage_on_accelerator_toggle = toggles["DisengageOnAccelerator"];
disengage_on_accelerator_toggle->setVisible(!params.getBool("AlwaysOnLateral"));
auto driver_camera_toggle = toggles["RecordFront"];
driver_camera_toggle->setVisible(!(params.getBool("DeviceManagement") && params.getBool("NoLogging") && params.getBool("NoUploads")));
auto experimental_mode_toggle = toggles["ExperimentalMode"];
auto op_long_toggle = toggles["ExperimentalLongitudinalEnabled"];
+13
View File
@@ -32,6 +32,18 @@ AbstractAlert::AbstractAlert(bool hasRebootBtn, QWidget *parent) : QFrame(parent
footer_layout->addWidget(dismiss_btn, 0, Qt::AlignBottom | Qt::AlignLeft);
QObject::connect(dismiss_btn, &QPushButton::clicked, this, &AbstractAlert::dismiss);
disable_check_btn = new QPushButton(tr("Disable Internet Check"));
disable_check_btn->setVisible(false);
disable_check_btn->setFixedSize(625, 125);
footer_layout->addWidget(disable_check_btn, 1, Qt::AlignBottom | Qt::AlignCenter);
QObject::connect(disable_check_btn, &QPushButton::clicked, [=]() {
params.putBool("SnoozeUpdate", true);
params.putBool("DeviceManagement", true);
params.putBool("OfflineMode", true);
});
QObject::connect(disable_check_btn, &QPushButton::clicked, this, &AbstractAlert::dismiss);
disable_check_btn->setStyleSheet(R"(color: white; background-color: #4F4F4F;)");
snooze_btn = new QPushButton(tr("Snooze Update"));
snooze_btn->setVisible(false);
snooze_btn->setFixedSize(550, 125);
@@ -107,6 +119,7 @@ int OffroadAlert::refresh() {
label->setVisible(!text.isEmpty());
alertCount += !text.isEmpty();
}
disable_check_btn->setVisible(!alerts["Offroad_ConnectivityNeeded"]->text().isEmpty());
snooze_btn->setVisible(!alerts["Offroad_ConnectivityNeeded"]->text().isEmpty());
return alertCount;
}
+1
View File
@@ -15,6 +15,7 @@ class AbstractAlert : public QFrame {
protected:
AbstractAlert(bool hasRebootBtn, QWidget *parent = nullptr);
QPushButton *disable_check_btn;
QPushButton *snooze_btn;
QVBoxLayout *scrollable_layout;
Params params;
+30 -1
View File
@@ -81,6 +81,34 @@ WiFiPromptWidget::WiFiPromptWidget(QWidget *parent) : QFrame(parent) {
}
stack->addWidget(uploading);
QWidget *notUploading = new QWidget;
QVBoxLayout *not_uploading_layout = new QVBoxLayout(notUploading);
not_uploading_layout->setContentsMargins(64, 56, 64, 56);
not_uploading_layout->setSpacing(36);
{
QHBoxLayout *title_layout = new QHBoxLayout;
{
QLabel *title = new QLabel(tr("Uploading disabled"));
title->setStyleSheet("font-size: 64px; font-weight: 600;");
title->setWordWrap(true);
title->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
title_layout->addWidget(title);
title_layout->addStretch();
QLabel *icon = new QLabel;
QPixmap pixmap("../frogpilot/assets/other_images/icon_wifi_uploading_disabled.svg");
icon->setPixmap(pixmap.scaledToWidth(120, Qt::SmoothTransformation));
title_layout->addWidget(icon);
}
not_uploading_layout->addLayout(title_layout);
QLabel *desc = new QLabel(tr("Toggle off the 'Disable Uploading' toggle to enable uploads."));
desc->setStyleSheet("font-size: 48px; font-weight: 400;");
desc->setWordWrap(true);
not_uploading_layout->addWidget(desc);
}
stack->addWidget(notUploading);
setStyleSheet(R"(
WiFiPromptWidget {
background-color: #333333;
@@ -99,5 +127,6 @@ void WiFiPromptWidget::updateState(const UIState &s) {
auto network_type = sm["deviceState"].getDeviceState().getNetworkType();
auto uploading = network_type == cereal::DeviceState::NetworkType::WIFI ||
network_type == cereal::DeviceState::NetworkType::ETHERNET;
stack->setCurrentIndex(uploading ? 1 : 0);
bool uploading_disabled = params.getBool("DeviceManagement") && params.getBool("NoUploads");
stack->setCurrentIndex(uploading_disabled ? 2 : uploading ? 1 : 0);
}
+3
View File
@@ -237,6 +237,7 @@ class Updater:
self._has_internet: bool = False
# FrogPilot variables
self.offline_mode = self.params.get_bool("DeviceManagement") and self.params.get_bool("OfflineMode")
@property
def has_internet(self) -> bool:
@@ -326,6 +327,8 @@ class Updater:
set_offroad_alert(alert, False)
now = datetime.datetime.utcnow()
if self.offline_mode:
last_update = now
dt = now - last_update
if failed_count > 15 and exception is not None and self.has_internet:
if is_tested_branch():