Add a StarPort section to the Developer page with the new pairing switch and an H.265 setting

The Developer page gets a heading row, StarPort, that groups the StarPort
settings: the New pairing experience switch (on unless turned off), Stay on
Wi-Fi (moved under the heading, same key, label and default) and Allow
H.265 video (off by default, daemon setting allow_hevc).

The heading is a row whose key starts with heading:, projected with
heading=true. It has no choices, is never available and cannot be changed,
and Galaxy draws it as a label. The new pairing switch is a plain file next
to the other StarPort data rather than a Params key, so it reads and changes
with the StarPort service down and needs no device rebuild; absent or
unreadable means on.
This commit is contained in:
dirwin31
2026-11-01 13:46:51 -08:00
committed by Danny
parent 6854118aa2
commit dbb1fe6547
13 changed files with 212 additions and 26 deletions
@@ -6,7 +6,8 @@ from openpilot.starpilot.longitudinal.voacc import KEY, DESCRIPTION
from openpilot.starpilot.ui.calibration_reset import calibration_reset
from openpilot.starpilot.saved_document import commit_exact
from openpilot.starpilot.saved_source import read_saved
from openpilot.starpilot.ui.feature_settings_state import FeatureRow, FeatureSettingsState
from openpilot.starpilot.system.starport import new_setup
from openpilot.starpilot.ui.feature_settings_state import HEADING_PREFIX, FeatureRow, FeatureSettingsState
STARPORT_WIFI_KEY = "StarPortDedicatedWifi"
@@ -14,6 +15,13 @@ STARPORT_WIFI_DESCRIPTION = ("Experimental. Join the car's Wi-Fi on a second int
"phone hotspot during wireless StarPort. Applies from the next StarPort connection.")
CALIBRATION_RESET = "reset_calibration"
CALIBRATION_RESET_DESCRIPTION = "Clear camera and steering calibration. The device recalibrates on the next drive."
STARPORT_HEADING_KEY = HEADING_PREFIX + "starport"
STARPORT_NEW_SETUP_KEY = "StarPortNewSetup"
STARPORT_NEW_SETUP_DESCRIPTION = ("Guided StarPort setup with a live checklist of what is being tried. Turn off to use the classic " +
"setup screens. Applies the next time the setup screen opens.")
STARPORT_HEVC_KEY = "StarPortAllowHevc"
STARPORT_HEVC_DESCRIPTION = ("Experimental. Only for a car that offers H.265 and no H.264 video. Cars that offer H.264 are not " +
"affected. Applies from the next StarPort connection.")
DRIVER_MONITORING_RESET = "reset_driver_monitoring"
DRIVER_MONITORING_RESET_DESCRIPTION = "Clear saved wheel-side detection. Automatic detection restarts on the next drive."
@@ -25,14 +33,40 @@ class DeveloperSettingsOwner:
self.panda_wake = panda_wake
self.starport = starport # returns the StarPort daemon client
def _starport_enabled(self):
def _starport_status(self):
if self.starport is None:
return None
try:
return bool(self.starport().call("status")["status"].get("dedicated_wifi_interface"))
status = self.starport().call("status")["status"]
return status if isinstance(status, dict) else None
except (OSError, RuntimeError, ValueError, KeyError, TypeError):
return None # the service is off; there is nothing to configure
def _starport_enabled(self):
status = self._starport_status()
return None if status is None else bool(status.get("dedicated_wifi_interface"))
def _starport_hevc(self):
status = self._starport_status()
return None if status is None else bool(status.get("allow_hevc"))
def _starport_rows(self, parked):
"""The StarPort section. The switch back to classic setup is always listed; the daemon's settings only while it runs."""
new_setup_on = new_setup.enabled()
held = "Park the vehicle to change this setting."
rows = [FeatureRow(STARPORT_HEADING_KEY, "StarPort", "", available=False),
FeatureRow(STARPORT_NEW_SETUP_KEY, "StarPort: New pairing experience", "On" if new_setup_on else "Off",
b"1" if new_setup_on else b"0", ("Off", "On"), available=parked,
reason=STARPORT_NEW_SETUP_DESCRIPTION if parked else held, default_value="On")]
status = self._starport_status()
if status is not None:
enabled, hevc = bool(status.get("dedicated_wifi_interface")), bool(status.get("allow_hevc"))
rows.append(FeatureRow(STARPORT_WIFI_KEY, "StarPort: Stay on Wi-Fi", "On" if enabled else "Off", b"1" if enabled else b"0",
("Off", "On"), available=parked, reason=STARPORT_WIFI_DESCRIPTION if parked else held, default_value="On"))
rows.append(FeatureRow(STARPORT_HEVC_KEY, "StarPort: Allow H.265 video", "On" if hevc else "Off", b"1" if hevc else b"0",
("Off", "On"), available=parked, reason=STARPORT_HEVC_DESCRIPTION if parked else held, default_value="Off"))
return tuple(rows)
def _driver_monitoring_reset_allowed(self):
return self.authorized() and not self.params.get_bool("IsDriverViewEnabled")
@@ -62,11 +96,7 @@ class DeveloperSettingsOwner:
firmware_rows = (() if self.panda_wake is None else
tuple(replace(item, vehicle_fingerprint=item.capability[0])
for item in self.panda_wake.rows(parked) if item.key == "IgnoreIgnitionLine"))
enabled = self._starport_enabled()
starport_rows = () if enabled is None else (
FeatureRow(STARPORT_WIFI_KEY, "StarPort: Stay on Wi-Fi", "On" if enabled else "Off", b"1" if enabled else b"0", ("Off", "On"),
available=parked, reason=STARPORT_WIFI_DESCRIPTION if parked else "Park the vehicle to change this setting.",
default_value="On"),)
starport_rows = self._starport_rows(parked)
summary = "Changes apply next drive. Panda firmware changes require a device restart." if firmware_rows else "Changes apply next drive."
return FeatureSettingsState("developer", "Developer driving options", summary,
(row, reset_row, calibration_row, *firmware_rows, *starport_rows), parked)
@@ -96,6 +126,10 @@ class DeveloperSettingsOwner:
return self.panda_wake is not None and self.panda_wake.apply(request)
if request.key == STARPORT_WIFI_KEY:
return self._apply_starport(request)
if request.key == STARPORT_HEVC_KEY:
return self._apply_hevc(request)
if request.key == STARPORT_NEW_SETUP_KEY:
return self._apply_new_setup(request)
if request.key != KEY or request.value not in ("Off", "On") or request.expected not in (None, b"0", b"1"):
return False
result = commit_exact(self.params, key=request.key, max_bytes=8, raw=b"1" if request.value == "On" else b"0",
@@ -112,3 +146,20 @@ class DeveloperSettingsOwner:
except (OSError, RuntimeError, ValueError):
return False
return self._starport_enabled() == (request.value == "On")
def _apply_hevc(self, request):
enabled, client = self._starport_hevc(), self.starport
if (enabled is None or client is None or request.value not in ("Off", "On") or request.expected != (b"1" if enabled else b"0") or
not self.authorized()):
return False
try:
client().call("set_allow_hevc", enabled=request.value == "On")
except (OSError, RuntimeError, ValueError):
return False
return self._starport_hevc() == (request.value == "On")
def _apply_new_setup(self, request):
current = new_setup.enabled()
if request.value not in ("Off", "On") or request.expected != (b"1" if current else b"0") or not self.authorized():
return False
return new_setup.set_enabled(request.value == "On")
@@ -90,6 +90,10 @@ DESCRIPTIONS = {
'RemoteStartBootsComma': 'Wakes comma during GM remote start.',
'HKGRemoteStartBootsComma': 'Wakes comma during Hyundai, Kia or Genesis remote climate operation.',
'IgnoreIgnitionLine': 'Uses GM CAN ignition instead of the harness ignition signal.',
'heading:starport': 'Settings for connecting Android Auto to the car through StarPort.',
'StarPortNewSetup': 'Shows the guided StarPort setup with a live checklist instead of the classic setup screens.',
'StarPortAllowHevc': 'Lets a car that offers only H.265 video receive H.265; a car with an H.264 mode keeps H.264.',
'StarPortDedicatedWifi': "Joins the car's Wi-Fi on a second interface so the comma stays on its home Wi-Fi or phone hotspot.",
'TeslaWakeOnCAN': 'Wakes comma when the Tesla wakes up, before you press the brake.',
'RadarRecoveryAlert': 'Play a chime and show a brief message when a radar fault clears. You must re-engage manually.',
'CameraView': 'Chooses the camera view shown on the driving screen.',
@@ -158,6 +162,9 @@ DESCRIPTIONS = {
# These are initialization explanations, not a second defaults table.
INITIALIZATION = {
'StarPortNewSetup': 'Applies the next time the setup screen opens.',
'StarPortAllowHevc': 'Applies from the next StarPort connection.',
'StarPortDedicatedWifi': 'Applies from the next StarPort connection.',
'LateralControllerSelection': ('Applies when driving processes next start: the controller class, vehicle policy and ' +
'PID/filter state are constructed together.'),
'UseStarPilotLongitudinalPlanner': 'Applies when the planner next starts: each choice runs a different planner process with its own subscriptions and state.',
+3 -2
View File
@@ -27,7 +27,7 @@ from openpilot.starpilot.audio.alert_volume import SPECS as SOUND_SPECS
from openpilot.starpilot.ui.presentation import Profile
from openpilot.common.hardware import HARDWARE
from openpilot.starpilot.ui.feature_settings_state import (
FeatureRow, FeatureSettingsRequest, FEATURE_CONFIRM_ACTIONS, is_long_confirm_action, row_change, row_default,
FeatureRow, FeatureSettingsRequest, FEATURE_CONFIRM_ACTIONS, is_heading, is_long_confirm_action, row_change, row_default,
)
from openpilot.starpilot.saved_source import read_saved
from openpilot.starpilot.galaxy.developer_settings import CALIBRATION_RESET, DRIVER_MONITORING_RESET, DeveloperSettingsOwner
@@ -392,7 +392,8 @@ def _projection(row: FeatureRow) -> dict:
"confirm": bool(row.key in CONFIRM_ACTIONS or is_long_confirm_action(row.key) or
row.key in (PIP_RESET, PIP_EDITOR, VASM_RESET, VASM_ANNOTATION) or row.key.startswith(PIP_FORMAT_PREFIX)),
"repairValue": row.repair_value, "defaultValue": row.default_value, "resetAvailable": row_default(row) is not None,
"displayScale": "lane-strength" if row.key == "LaneCenteringStrength" else None}
"displayScale": "lane-strength" if row.key == "LaneCenteringStrength" else None,
"heading": is_heading(row.key)}
def _question(row: FeatureRow, request: FeatureSettingsRequest) -> str:
@@ -57,13 +57,6 @@
"LoudBlindspotAlert",
"LoudBlindspotAlertWhenDisengaged",
"NostalgiaMode",
"slc:offset:1",
"slc:offset:2",
"slc:offset:3",
"slc:offset:4",
"slc:offset:5",
"slc:offset:6",
"slc:offset:7",
"PIPPreviewEnabled",
"PIPPreviewInvert",
"PIPPreviewShowOnBSM",
@@ -106,6 +99,9 @@
"StandardJerkSpeed",
"StandardJerkSpeedDecrease",
"StarPilotDisplayPreferencesEnabled",
"StarPortAllowHevc",
"StarPortDedicatedWifi",
"StarPortNewSetup",
"SteerFriction",
"SteerLatAccel",
"StockConfidenceBallWidget",
@@ -166,6 +162,7 @@
"display:auto:ScreenBrightness",
"display:auto:ScreenBrightnessOnroad",
"enable_human_turn_detection_curv",
"heading:starport",
"lane_change:auto",
"lane_change:close_gap",
"lane_change:close_gap_seconds",
@@ -249,7 +246,6 @@
"profile:aggressive:following:8",
"profile:aggressive:following:9",
"profile:global_acceleration",
"profile:stopped_gap",
"profile:global_braking",
"profile:relaxed:acceleration",
"profile:relaxed:acceleration:0",
@@ -317,6 +313,7 @@
"profile:standard:following:7",
"profile:standard:following:8",
"profile:standard:following:9",
"profile:stopped_gap",
"profile:traffic:acceleration",
"profile:traffic:acceleration:0",
"profile:traffic:acceleration:1",
@@ -357,6 +354,13 @@
"sentry:reset",
"sentry:sensitivity",
"sentry:warning",
"slc:offset:1",
"slc:offset:2",
"slc:offset:3",
"slc:offset:4",
"slc:offset:5",
"slc:offset:6",
"slc:offset:7",
"slc_reset",
"sounds:auto:DisengageVolume",
"sounds:auto:EngageVolume",
@@ -3,14 +3,18 @@
from dataclasses import replace
from pathlib import Path
from types import SimpleNamespace
from unittest import mock
from typing import cast
import tempfile
import unittest
from unittest.mock import patch
from openpilot.starpilot.galaxy.developer_settings import CALIBRATION_RESET, DRIVER_MONITORING_RESET, STARPORT_WIFI_KEY, DeveloperSettingsOwner
from openpilot.starpilot.galaxy.developer_settings import (CALIBRATION_RESET, DRIVER_MONITORING_RESET, STARPORT_HEADING_KEY,
STARPORT_HEVC_KEY, STARPORT_NEW_SETUP_KEY, STARPORT_WIFI_KEY,
DeveloperSettingsOwner)
from openpilot.starpilot.galaxy.settings import AuthorityContext, ContextSource, SettingsChanged, SettingsGateway
from openpilot.starpilot.longitudinal.voacc import KEY, selected
from openpilot.starpilot.system.starport import new_setup
from openpilot.starpilot.ui.feature_settings_state import FeatureSettingsRequest
@@ -40,7 +44,7 @@ class FileParams:
class FakeStarPort:
def __init__(self, enabled=False, running=True):
self.enabled, self.running = enabled, running
self.enabled, self.running, self.hevc = enabled, running, False
def call(self, command, **payload):
if not self.running:
@@ -48,7 +52,10 @@ class FakeStarPort:
if command == "set_dedicated_wifi":
self.enabled = payload["enabled"]
return {"ok": True}
return {"ok": True, "status": {"dedicated_wifi_interface": self.enabled}}
if command == "set_allow_hevc":
self.hevc = payload["enabled"]
return {"ok": True}
return {"ok": True, "status": {"dedicated_wifi_interface": self.enabled, "allow_hevc": self.hevc}}
class DeveloperSettingsTest(unittest.TestCase):
@@ -60,6 +67,11 @@ class DeveloperSettingsTest(unittest.TestCase):
self.cp = SimpleNamespace(openpilotLongitudinalControl=True, notCar=False, dashcamOnly=False, passive=False)
self.parked = True
self.owner = DeveloperSettingsOwner(self.params, lambda: self.parked)
flag = Path(directory.name) / "new_setup"
patch = mock.patch.object(new_setup, "FLAG_PATH", flag)
patch.start()
self.addCleanup(patch.stop)
self.flag = flag
def test_default_off_strict_selection_and_vehicle_admission(self):
self.assertEqual(self.owner.snapshot().rows[0].value, "Off")
@@ -172,6 +184,52 @@ class DeveloperSettingsTest(unittest.TestCase):
self.assertFalse(self.owner.apply(FeatureSettingsRequest(DRIVER_MONITORING_RESET, b"1", "confirm", confirmation=True)))
self.assertTrue(Path(self.params.get_param_path("IsRhdDetected")).exists())
def test_starport_section_has_a_heading_and_the_escape_hatch_even_with_the_service_off(self):
rows = self.owner.snapshot().rows
keys = [row.key for row in rows]
heading = rows[keys.index(STARPORT_HEADING_KEY)]
self.assertEqual((heading.label, heading.value, heading.available, heading.choices), ("StarPort", "", False, ()))
self.assertEqual(keys[keys.index(STARPORT_HEADING_KEY) + 1], STARPORT_NEW_SETUP_KEY) # the heading groups what follows
self.assertNotIn(STARPORT_WIFI_KEY, keys)
self.assertNotIn(STARPORT_HEVC_KEY, keys)
self.assertFalse(self.owner.apply(FeatureSettingsRequest(STARPORT_HEADING_KEY, b"", "On"))) # a heading is never a control
def test_new_pairing_experience_defaults_on_and_the_classic_screens_are_one_switch_away(self):
row = next(row for row in self.owner.snapshot().rows if row.key == STARPORT_NEW_SETUP_KEY)
self.assertEqual((row.value, row.source, row.choices, row.default_value, row.available), ("On", b"1", ("Off", "On"), "On", True))
self.assertFalse(self.owner.apply(FeatureSettingsRequest(STARPORT_NEW_SETUP_KEY, b"0", "On"))) # stale view
self.assertFalse(self.owner.apply(FeatureSettingsRequest(STARPORT_NEW_SETUP_KEY, b"1", "maybe")))
self.assertTrue(self.owner.apply(FeatureSettingsRequest(STARPORT_NEW_SETUP_KEY, b"1", "Off")))
self.assertFalse(new_setup.enabled())
self.assertEqual(next(r for r in self.owner.snapshot().rows if r.key == STARPORT_NEW_SETUP_KEY).value, "Off")
self.parked = False
self.assertFalse(self.owner.apply(FeatureSettingsRequest(STARPORT_NEW_SETUP_KEY, b"0", "On")))
self.parked = True
self.assertTrue(self.owner.apply(FeatureSettingsRequest(STARPORT_NEW_SETUP_KEY, b"0", "On")))
self.assertTrue(new_setup.enabled())
def test_unreadable_or_odd_flag_means_on(self):
self.flag.write_text("garbage")
self.assertTrue(new_setup.enabled())
self.flag.unlink()
self.assertTrue(new_setup.enabled())
def test_allow_h265_toggle_defaults_off_and_follows_the_daemon(self):
service = FakeStarPort()
owner = DeveloperSettingsOwner(self.params, lambda: self.parked, starport=lambda: service)
rows = owner.snapshot().rows
keys = [row.key for row in rows]
self.assertEqual(keys[keys.index(STARPORT_HEADING_KEY):], [STARPORT_HEADING_KEY, STARPORT_NEW_SETUP_KEY, STARPORT_WIFI_KEY, STARPORT_HEVC_KEY])
row = rows[keys.index(STARPORT_HEVC_KEY)]
self.assertEqual((row.value, row.default_value, row.available), ("Off", "Off", True))
self.assertTrue(owner.apply(FeatureSettingsRequest(STARPORT_HEVC_KEY, row.source, "On")))
self.assertTrue(service.hevc)
self.assertFalse(owner.apply(FeatureSettingsRequest(STARPORT_HEVC_KEY, row.source, "Off"))) # stale view
self.parked = False
self.assertFalse(owner.apply(FeatureSettingsRequest(STARPORT_HEVC_KEY, b"1", "Off")))
self.parked = True
service.running = False
self.assertFalse(owner.apply(FeatureSettingsRequest(STARPORT_HEVC_KEY, b"1", "Off")))
class CalibrationResetSettingsTest(unittest.TestCase):
setUp = DeveloperSettingsTest.setUp
@@ -227,3 +227,15 @@ for (const row of [{ value: "30", minimum: 1, maximum: 30, step: 1, unit: "h" },
{ value: "11.8", minimum: 11.8, maximum: 12.5, step: .1, unit: "V" }]) {
assert.equal(settingControl(row), "slider")
}
// A section heading (for example "StarPort" on the Developer page) is a label only: no control, no readout, no default button.
{
const heading = { label: "StarPort", value: "", heading: true, available: false, choices: [], key: "heading:starport" }
assert.equal(settingControl(heading), "readout")
const template = GalaxySettingRow.template
assert.match(template, /'gx-row--heading': row\.heading/)
assert.match(template, /v-else-if="!row\.heading" class="gx-row__value gx-row__readout"/)
assert.match(template, /showDefault && !row\.heading/)
assert.match(template, /presentedRow\.reason && !row\.heading/)
}
console.log("Settings controls: section headings render as labels only")
@@ -1711,6 +1711,9 @@ input[type="checkbox"]:disabled { opacity: .4; cursor: not-allowed; }
.gx-inset { margin: var(--sp-4); max-width: calc(100% - 2 * var(--sp-4)); }
.gx-text-danger { color: var(--error); }
.gx-row.gx-row--borderless { border-top: 0; }
/* A section title inside a settings page: a label only, never dimmed like an unavailable control. */
.gx-row.gx-row--heading, .gx-row.gx-row--heading.disabled { opacity: 1; padding-top: 1.25rem; }
.gx-row--heading .gx-row__label { font-weight: 700; letter-spacing: .04em; text-transform: uppercase; opacity: .75; }
.gx-row--wrap { flex-wrap: wrap; }
.gx-row__info.gx-row__info--wide { flex: 1 1 180px; }
.gx-filter-field { flex: 1 1 14rem; min-width: 0; }
@@ -215,14 +215,14 @@ export const GalaxySettingRow = {
},
beforeUnmount() { this.clearHoldTimer() },
template: `
<div class="gx-row" :class="{ disabled: dimmed, 'gx-row--stack': control === 'slider' }" :inert="busy || updating" :aria-busy="busy || updating || undefined">
<div class="gx-row" :class="{ disabled: dimmed, 'gx-row--stack': control === 'slider', 'gx-row--heading': row.heading }" :role="row.heading ? 'heading' : undefined" :aria-level="row.heading ? 3 : undefined" :inert="busy || updating" :aria-busy="busy || updating || undefined">
<div class="gx-row__info">
<span class="gx-row__label">{{ row.label }}</span>
<span v-if="presentedRow.reason" class="gx-row__desc">{{ ' ' + presentedRow.reason.replace('https://firestar.link/discord', '') }}</span>
<span v-if="presentedRow.reason && !row.heading" class="gx-row__desc">{{ ' ' + presentedRow.reason.replace('https://firestar.link/discord', '') }}</span>
<a v-if="presentedRow.reason?.includes('https://firestar.link/discord')" class="gx-btn gx-btn--tonal" href="https://firestar.link/discord" target="_blank" rel="noopener">StarPilot Discord</a>
<span v-if="control === 'group' || control === 'action'" class="gx-row__desc">{{ presentedRow.value }}</span>
</div>
<button v-if="control !== 'slider' && showDefault" type="button"
<button v-if="control !== 'slider' && showDefault && !row.heading" type="button"
class="gx-btn gx-btn--tonal gx-setting-default" :disabled="dimmed || !row.resetAvailable"
:aria-label="'Reset ' + row.label + ' to default'" :title="'Default: ' + presentedRow.defaultValue"
@click="$emit('reset-default', index)">Default</button>
@@ -249,6 +249,6 @@ export const GalaxySettingRow = {
</GalaxySelect>
<button v-else-if="control === 'group'" type="button" class="gx-btn gx-btn--tonal" :disabled="dimmed" @click="$emit('open', row.page)">Manage</button>
<button v-else-if="control === 'action' && row.action" type="button" class="gx-btn gx-btn--tonal" :disabled="dimmed" @click="$emit('review', index, row.confirm ? 0 : 1)">{{ row.repairValue === 'Reset' || /reset|default/i.test(row.label) ? 'Reset' : row.repairValue ? 'Set ' + row.repairValue : row.label }}</button>
<span v-else class="gx-row__value gx-row__readout">{{ displayValue }}</span>
<span v-else-if="!row.heading" class="gx-row__value gx-row__readout">{{ displayValue }}</span>
</div>`,
}
@@ -118,6 +118,8 @@ def handle(supervisor: Supervisor, request: dict[str, Any], verifier: StarPortSo
supervisor.set_auto_connect(bool(request.get("enabled", True)))
elif command == "set_dedicated_wifi":
supervisor.set_dedicated_wifi(request.get("enabled") is True)
elif command == "set_allow_hevc":
supervisor.set_allow_hevc(request.get("enabled") is True)
elif command == "select_receiver":
supervisor.select_receiver(str(request.get("address", "")), str(request.get("name", "")))
elif command == "forget_receiver":
@@ -141,6 +141,7 @@ DEFAULT_CONFIG = {
"render_profile_kb": 256, # size cap per render_profile file
"wifi_interface": "wlan0",
"dedicated_wifi_interface": True, # join the car on its own aa0 station so wlan0 stays on home Wi-Fi
"allow_hevc": False, # offer H.265 when the car offers no usable H.264 mode (Galaxy Developer > StarPort)
"device_name": "StarPilot",
"version_status": 0, # WifiVersionResponse status (0 = success) for receivers that negotiate a version
"phone_class": True, # while pairing/connecting, present as a phone: HFP gateway + smartphone Class of Device
@@ -189,6 +190,7 @@ def load_config(path: Path | None = None) -> dict:
if config["usb_mode"] not in ("auto", "handshake", "direct"):
config["usb_mode"] = "auto"
config["bitrate_kbps"] = max(1000, min(12000, int(config["bitrate_kbps"])))
config["allow_hevc"] = config["allow_hevc"] is True
if config["rate_control"] not in ("cbr", "vbr"):
config["rate_control"] = "cbr"
config["render_profile_kb"] = max(16, min(4096, int(config["render_profile_kb"])))
@@ -0,0 +1,30 @@
"""The "New pairing experience" switch (Galaxy Developer > StarPort), on unless the owner turned it off.
A plain file beside the other StarPort data, not a Params key: it is the way back to the classic screens, so it must
read and change with the StarPort service down or broken, and it needs no device rebuild.
"""
from pathlib import Path
from openpilot.starpilot.system.starport.identity import DATA_DIR
FLAG_PATH = DATA_DIR / "new_setup"
def enabled(path: Path | None = None) -> bool:
"""Absent, unreadable or unrecognised means on; only an explicit 0 turns the new flow off."""
try:
return (path or FLAG_PATH).read_text().strip() != "0"
except (OSError, UnicodeError):
return True
def set_enabled(value: bool, path: Path | None = None) -> bool:
target = path or FLAG_PATH
try:
target.parent.mkdir(mode=0o700, parents=True, exist_ok=True)
temporary = target.with_name(f".{target.name}.tmp")
temporary.write_text("1" if value else "0")
temporary.replace(target)
except OSError:
return False
return enabled(target) == value
@@ -69,7 +69,7 @@ LINK_CHECK_SLOW = 1.0 # a link check slower than this is logged (NetworkM
STREAM_STALL_LOG = 1.0 # a streaming loop pass slower than this is logged
REPORTED_SETTINGS = ("connection", "usb_mode", "view", "encoder", "fps", "bitrate_kbps", "rate_control", "gpu_nv12",
"async_readback", "wifi_interface", "dedicated_wifi_interface", "verify_head_unit", "version_status",
"rfcomm_channel", "phone_class", "auto_connect")
"rfcomm_channel", "phone_class", "auto_connect", "allow_hevc")
def encoder_preference(configured: str) -> str:
@@ -405,6 +405,7 @@ class Supervisor:
status["pairing_ready"] = self._pairing_active()
status["auto_connect"] = bool(self.config["auto_connect"])
status["dedicated_wifi_interface"] = bool(self.config["dedicated_wifi_interface"])
status["allow_hevc"] = bool(self.config["allow_hevc"])
status["auto_paused"] = self.auto.suppressed
status["recent"] = list(self.log.recent)[-8:]
return status
@@ -433,6 +434,13 @@ class Supervisor:
identity_store.save_config(self.config)
self.log("dedicated_wifi_selected", enabled=bool(enabled))
def set_allow_hevc(self, enabled: bool) -> None:
"""Let a car that offers only H.265 get H.265 video; used from the next session. Cars with an H.264 mode never change."""
with self._lock:
self.config["allow_hevc"] = bool(enabled)
identity_store.save_config(self.config)
self.log("allow_hevc_selected", enabled=bool(enabled))
def _adapter_choice_needed(self) -> bool:
return self.car_type() == "adapter" and not self.config.get("car_profile_override")
@@ -75,6 +75,14 @@ FEATURE_CONFIRM_ACTIONS = (TORQUE_CONFIRM_ACTIONS | SLC_CONFIRM_ACTIONS | LANE_C
CURVE_CONFIRM_ACTIONS | CONDITIONAL_CONFIRM_ACTIONS | {"reset_profiles", "pip:reset", "sentry:reset"})
HEADING_PREFIX = "heading:"
def is_heading(key: str) -> bool:
"""A section title inside a page: shown like a row but never a control, and never a change request."""
return key.startswith(HEADING_PREFIX)
@dataclass(frozen=True)
class FeatureRow:
key: str