diff --git a/openpilot/common/params_keys.h b/openpilot/common/params_keys.h index 3c5f30ab3d..6b6328df58 100644 --- a/openpilot/common/params_keys.h +++ b/openpilot/common/params_keys.h @@ -132,6 +132,7 @@ inline static std::unordered_map keys = { {"UptimeOnroad", {PERSISTENT, FLOAT, "0.0"}}, {"ChestnutActive", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION | CLEAR_ON_IGNITION_ON, BOOL}}, {"ChestnutLoading", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION | CLEAR_ON_IGNITION_ON, BOOL}}, + {"AuxPowerSave", {PERSISTENT | BACKUP, BOOL}}, {"Version", {PERSISTENT, STRING}}, // --- sunnypilot params --- // diff --git a/openpilot/selfdrive/ui/ui_state.py b/openpilot/selfdrive/ui/ui_state.py index 4d93e1aacb..124852e4ba 100644 --- a/openpilot/selfdrive/ui/ui_state.py +++ b/openpilot/selfdrive/ui/ui_state.py @@ -220,6 +220,7 @@ class UIState(UIStateSP): ChestnutState.UNCOMPILED if detected else ChestnutState.DISCONNECTED) return + self.chestnut_present = self.chestnut_present or detected model_seen = self.sm.recv_frame["modelV2"] > self.started_frame if not self.chestnut_present: self.chestnut_state = ChestnutState.DISCONNECTED diff --git a/openpilot/sunnypilot/sunnylink/settings_ui.json b/openpilot/sunnypilot/sunnylink/settings_ui.json index 63bf342fcb..f0cbc07837 100644 --- a/openpilot/sunnypilot/sunnylink/settings_ui.json +++ b/openpilot/sunnypilot/sunnylink/settings_ui.json @@ -1675,6 +1675,12 @@ "widget": "toggle", "title": "Onroad Uploads" }, + { + "key": "AuxPowerSave", + "widget": "toggle", + "title": "Disable Aux Port When Offroad", + "description": "Power off the aux USB-C port while offroad to save power. It powers back on automatically when you go onroad." + }, { "key": "MaxTimeOffroad", "widget": "option", diff --git a/openpilot/sunnypilot/sunnylink/settings_ui_src/pages/device.yaml b/openpilot/sunnypilot/sunnylink/settings_ui_src/pages/device.yaml index bf5f7883ab..d519a1f9b9 100644 --- a/openpilot/sunnypilot/sunnylink/settings_ui_src/pages/device.yaml +++ b/openpilot/sunnypilot/sunnylink/settings_ui_src/pages/device.yaml @@ -30,6 +30,10 @@ sections: - key: OnroadUploads widget: toggle title: Onroad Uploads + - key: AuxPowerSave + widget: toggle + title: Disable Aux Port When Offroad + description: Power off the aux USB-C port while offroad to save power. It powers back on automatically when you go onroad. - key: MaxTimeOffroad widget: option title: Max Time Offroad diff --git a/openpilot/system/hardware/hardwared.py b/openpilot/system/hardware/hardwared.py index dd9c92269b..e6e8486a1e 100755 --- a/openpilot/system/hardware/hardwared.py +++ b/openpilot/system/hardware/hardwared.py @@ -21,6 +21,7 @@ from openpilot.selfdrive.selfdrived.alertmanager import set_offroad_alert from openpilot.common.hardware import HARDWARE, COMMA_HARDWARE from openpilot.common.basedir import BASEDIR from openpilot.common.hardware.usb import CHESTNUT_FW_VERSION, CHESTNUT_ROM_USB_IDS, CHESTNUT_USB_IDS, get_usb_state, get_usb_topology, set_usb_state +from openpilot.system.hardware.chestnut.flash import VBUS_PATH from openpilot.common.linux import LinuxSystemStats from openpilot.system.loggerd.config import get_available_percent from openpilot.common.swaglog import cloudlog @@ -49,6 +50,10 @@ class Chestnut: self.attempts = 0 self.last_attempt = 0. self.flashed = False + self.vbus_on = None + self.params = Params() + self.powersave = False + self.last_offroad = None def flash(self) -> None: ret = subprocess.run(["sudo", sys.executable, os.path.join(BASEDIR, "openpilot/system/hardware/chestnut/flash.py"), CHESTNUT_FW_VERSION], @@ -56,9 +61,19 @@ class Chestnut: cloudlog.event("chestnut flash done", returncode=ret.returncode, output=ret.stdout[-1000:], error=ret.returncode != 0) self.flashed = ret.returncode == 0 + def set_vbus(self, on: bool) -> None: + if on == self.vbus_on: + return + subprocess.run(["sudo", "tee", VBUS_PATH], input=b"1" if on else b"0", stdout=subprocess.DEVNULL, check=False) + self.vbus_on = on + def update(self, offroad: bool, usb_state: list[dict]) -> None: mismatch = any((d["vendorId"], d["productId"]) in CHESTNUT_USB_IDS + CHESTNUT_ROM_USB_IDS and d["product"] != f"custom {CHESTNUT_FW_VERSION}-CLEAN" for d in usb_state) + if offroad != self.last_offroad: + self.powersave = self.params.get_bool("AuxPowerSave") + self.last_offroad = offroad + self.set_vbus((not offroad or mismatch) or not self.powersave) if not mismatch: self.flashed = False return