mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-07-06 14:16:39 +08:00
Migration
Migration Banner Auto Push to StarPilot / Update Fingerprints
This commit is contained in:
@@ -18,6 +18,7 @@ from openpilot.selfdrive.car import gen_empty_fingerprint
|
||||
from openpilot.system.version import get_build_metadata
|
||||
|
||||
FRAME_FINGERPRINT = 100 # 1s
|
||||
SOURCE_BRANCH_FILE = "/data/media/0/starpilot_source_branch"
|
||||
|
||||
EventName = car.CarEvent.EventName
|
||||
FrogPilotEventName = custom.FrogPilotCarEvent.EventName
|
||||
@@ -189,6 +190,64 @@ def get_car_interface(CP, FPCP):
|
||||
CarInterface, CarController, CarState = interfaces[CP.carFingerprint]
|
||||
return CarInterface(CP, FPCP, CarController, CarState)
|
||||
|
||||
def get_cached_car_fingerprint(params: Params) -> str | None:
|
||||
for key in ("CarParamsPersistent", "CarParamsCache", "CarParams"):
|
||||
cp_bytes = params.get(key)
|
||||
if cp_bytes is None:
|
||||
continue
|
||||
try:
|
||||
with car.CarParams.from_bytes(cp_bytes) as cached_cp:
|
||||
if cached_cp.carFingerprint:
|
||||
return cached_cp.carFingerprint
|
||||
except Exception:
|
||||
continue
|
||||
return None
|
||||
|
||||
def clear_stale_car_params(params: Params, candidate: str) -> None:
|
||||
cached_fingerprint = get_cached_car_fingerprint(params)
|
||||
if cached_fingerprint is None or cached_fingerprint == candidate:
|
||||
return
|
||||
|
||||
stale_keys = (
|
||||
"CarParams",
|
||||
"CarParamsCache",
|
||||
"CarParamsPersistent",
|
||||
"FrogPilotCarParams",
|
||||
"FrogPilotCarParamsPersistent",
|
||||
"CarModelName",
|
||||
)
|
||||
for key in stale_keys:
|
||||
params.remove(key)
|
||||
|
||||
cloudlog.warning("cleared stale car params after fingerprint change: %s -> %s", cached_fingerprint, candidate)
|
||||
|
||||
def migrate_legacy_bolt_candidate(candidate: str) -> str:
|
||||
source_branch = ""
|
||||
try:
|
||||
with open(SOURCE_BRANCH_FILE, encoding="utf-8") as f:
|
||||
source_branch = f.read().strip()
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
migration_branch = source_branch or get_build_metadata().channel
|
||||
replacements = {}
|
||||
if migration_branch in {"TorqueTune", "TorquePedal"}:
|
||||
replacements = {
|
||||
"CHEVROLET_BOLT_EUV": GM_CAR.CHEVROLET_BOLT_ACC_2022_2023,
|
||||
"CHEVROLET_BOLT_CC": GM_CAR.CHEVROLET_BOLT_CC_2022_2023,
|
||||
}
|
||||
elif migration_branch in {"TotallyTune", "StarPilot-2017", "StarPilot 2017"}:
|
||||
replacements = {
|
||||
"CHEVROLET_BOLT_CC": GM_CAR.CHEVROLET_BOLT_CC_2017,
|
||||
}
|
||||
elif migration_branch in {"StarPilot"}:
|
||||
replacements = {
|
||||
"CHEVROLET_BOLT_CC": GM_CAR.CHEVROLET_BOLT_CC_2019_2021,
|
||||
}
|
||||
|
||||
normalized_candidate = candidate[4:] if candidate.startswith("CAR.") else candidate
|
||||
return replacements.get(normalized_candidate, normalized_candidate)
|
||||
|
||||
|
||||
def get_car(logcan, sendcan, experimental_long_allowed, params, num_pandas=1, frogpilot_toggles=None):
|
||||
candidate, fingerprints, vin, car_fw, source, exact_match = fingerprint(logcan, sendcan, num_pandas)
|
||||
@@ -203,9 +262,23 @@ def get_car(logcan, sendcan, experimental_long_allowed, params, num_pandas=1, fr
|
||||
params.put_nonblocking("CarMake", candidate.split('_')[0].title())
|
||||
params.put_nonblocking("CarModel", candidate)
|
||||
|
||||
# Branch migration can leave legacy Bolt candidate names active in params/cache.
|
||||
# Remap the selected candidate itself so fingerprint selection and params stay in sync.
|
||||
migrated_candidate = migrate_legacy_bolt_candidate(candidate)
|
||||
if candidate != migrated_candidate:
|
||||
cloudlog.warning("legacy Bolt candidate migration: %s -> %s", candidate, migrated_candidate)
|
||||
candidate = migrated_candidate
|
||||
params.put_nonblocking("CarMake", candidate.split('_')[0].title())
|
||||
params.put_nonblocking("CarModel", candidate)
|
||||
params.remove("CarModelName")
|
||||
|
||||
# VIN-based Bolt year mapping (selfdrive-only, bolt variants only)
|
||||
if not frogpilot_toggles.force_fingerprint and is_valid_vin(vin):
|
||||
bolt_variants = {
|
||||
"CHEVROLET_BOLT_EUV",
|
||||
"CHEVROLET_BOLT_CC",
|
||||
"CAR.CHEVROLET_BOLT_EUV",
|
||||
"CAR.CHEVROLET_BOLT_CC",
|
||||
GM_CAR.CHEVROLET_BOLT_ACC_2022_2023,
|
||||
GM_CAR.CHEVROLET_BOLT_CC_2022_2023,
|
||||
GM_CAR.CHEVROLET_BOLT_CC_2019_2021,
|
||||
@@ -235,12 +308,28 @@ def get_car(logcan, sendcan, experimental_long_allowed, params, num_pandas=1, fr
|
||||
candidate = vin_candidate
|
||||
params.put_nonblocking("CarMake", candidate.split('_')[0].title())
|
||||
params.put_nonblocking("CarModel", candidate)
|
||||
params.remove("CarModelName")
|
||||
cloudlog.warning("VIN Bolt override: %s -> %s", prev_candidate, candidate)
|
||||
|
||||
# Always prefer live fingerprint naming for Bolt variants to avoid stale manual labels.
|
||||
if candidate in {
|
||||
GM_CAR.CHEVROLET_BOLT_ACC_2022_2023,
|
||||
GM_CAR.CHEVROLET_BOLT_CC_2022_2023,
|
||||
GM_CAR.CHEVROLET_BOLT_CC_2019_2021,
|
||||
GM_CAR.CHEVROLET_BOLT_CC_2017,
|
||||
"CHEVROLET_BOLT_EUV",
|
||||
"CHEVROLET_BOLT_CC",
|
||||
"CAR.CHEVROLET_BOLT_EUV",
|
||||
"CAR.CHEVROLET_BOLT_CC",
|
||||
}:
|
||||
params.remove("CarModelName")
|
||||
|
||||
if frogpilot_toggles.block_user:
|
||||
candidate = MOCK.MOCK
|
||||
sentry.capture_block()
|
||||
|
||||
clear_stale_car_params(params, candidate)
|
||||
|
||||
CarInterface, _, _ = interfaces[candidate]
|
||||
CP = CarInterface.get_params(candidate, fingerprints, car_fw, experimental_long_allowed, frogpilot_toggles, docs=False)
|
||||
FPCP = CarInterface.get_frogpilot_params(candidate, fingerprints, car_fw, CP, frogpilot_toggles)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QMouseEvent>
|
||||
#include <QSet>
|
||||
#include <QStackedWidget>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
@@ -172,6 +173,22 @@ OffroadHome::OffroadHome(QWidget* parent) : QFrame(parent) {
|
||||
|
||||
main_layout->addLayout(header_layout);
|
||||
|
||||
branch_merge_banner = new QLabel(this);
|
||||
branch_merge_banner->setAlignment(Qt::AlignCenter);
|
||||
branch_merge_banner->setWordWrap(true);
|
||||
branch_merge_banner->setAttribute(Qt::WA_TransparentForMouseEvents, true);
|
||||
branch_merge_banner->setVisible(false);
|
||||
branch_merge_banner->setStyleSheet(R"(
|
||||
background-color: #E22C2C;
|
||||
color: white;
|
||||
border-radius: 16px;
|
||||
padding: 24px;
|
||||
font-size: 44px;
|
||||
font-weight: 700;
|
||||
)");
|
||||
branch_merge_banner->setText(tr("Branch Merge Notice: This branch is deprecated and has been merged into StarPilot. Please switch to the StarPilot branch."));
|
||||
main_layout->addWidget(branch_merge_banner);
|
||||
|
||||
// main content
|
||||
main_layout->addSpacing(25);
|
||||
center_layout = new QStackedLayout();
|
||||
@@ -268,10 +285,21 @@ void OffroadHome::hideEvent(QHideEvent *event) {
|
||||
}
|
||||
|
||||
void OffroadHome::refresh() {
|
||||
static const QSet<QString> deprecated_branches = {
|
||||
"TorqueTune",
|
||||
"TorquePedal",
|
||||
"Kaofui",
|
||||
"Red-Kao",
|
||||
"TotallyTune",
|
||||
"StarPilot-2017",
|
||||
"TRX",
|
||||
};
|
||||
|
||||
date->setText(QLocale(uiState()->language.mid(5)).toString(QDateTime::currentDateTime(), "dddd, MMMM d"));
|
||||
date->setVisible(util::system_time_valid());
|
||||
|
||||
version->setText(getBrand() + " v" + getVersion().left(14).trimmed() + " - " + processModelName(frogpilotUIState()->frogpilot_toggles.value("model_name").toString()));
|
||||
branch_merge_banner->setVisible(deprecated_branches.contains(QString::fromStdString(params.get("GitBranch"))));
|
||||
|
||||
bool updateAvailable = update_widget->refresh();
|
||||
int alerts = alerts_widget->refresh();
|
||||
|
||||
@@ -41,6 +41,7 @@ private:
|
||||
OffroadAlert* alerts_widget;
|
||||
QPushButton* alert_notif;
|
||||
QPushButton* update_notif;
|
||||
QLabel* branch_merge_banner;
|
||||
|
||||
// FrogPilot variables
|
||||
ElidedLabel* date;
|
||||
|
||||
@@ -92,6 +92,63 @@ def manager_init() -> None:
|
||||
params.put_bool("IsTestedBranch", build_metadata.tested_channel)
|
||||
params.put_bool("IsReleaseBranch", build_metadata.release_channel)
|
||||
|
||||
# Legacy Bolt fingerprint migration after branch consolidation
|
||||
bolt_source_branch_file = "/data/media/0/starpilot_source_branch"
|
||||
bolt_fingerprint_migration_flag_file = "/data/media/0/frogpilot_bolt_fingerprint_migrated.flag"
|
||||
source_branch = ""
|
||||
try:
|
||||
if os.path.exists(bolt_source_branch_file):
|
||||
with open(bolt_source_branch_file, encoding="utf-8") as f:
|
||||
source_branch = f.read().strip()
|
||||
except OSError:
|
||||
cloudlog.exception("failed reading StarPilot source branch file")
|
||||
|
||||
migration_branch = source_branch or build_metadata.channel
|
||||
replacements = {}
|
||||
if migration_branch in {"TorqueTune", "TorquePedal"}:
|
||||
replacements = {
|
||||
"CHEVROLET_BOLT_EUV": "CHEVROLET_BOLT_ACC_2022_2023",
|
||||
"CHEVROLET_BOLT_CC": "CHEVROLET_BOLT_CC_2022_2023",
|
||||
}
|
||||
elif migration_branch in {"TotallyTune", "StarPilot-2017", "StarPilot 2017"}:
|
||||
replacements = {
|
||||
"CHEVROLET_BOLT_CC": "CHEVROLET_BOLT_CC_2017",
|
||||
}
|
||||
elif migration_branch in {"StarPilot"}:
|
||||
replacements = {
|
||||
"CHEVROLET_BOLT_CC": "CHEVROLET_BOLT_CC_2019_2021",
|
||||
}
|
||||
|
||||
migrated_values = []
|
||||
if replacements:
|
||||
for param_key in ("CarModel", "CarModelName"):
|
||||
current_value = params.get(param_key, encoding='utf-8')
|
||||
normalized_value = current_value[4:] if current_value is not None and current_value.startswith("CAR.") else current_value
|
||||
if normalized_value in replacements:
|
||||
new_value = replacements[normalized_value]
|
||||
params.put(param_key, new_value)
|
||||
params_cache.put(param_key, new_value)
|
||||
migrated_values.append(f"{param_key}: {current_value} -> {new_value}")
|
||||
|
||||
if migrated_values:
|
||||
cloudlog.info(f"migrated legacy bolt fingerprint values from branch '{migration_branch}' (source='{source_branch}'): {', '.join(migrated_values)}")
|
||||
|
||||
# Keep Bolt display label aligned with live fingerprint selection
|
||||
bolt_models = {
|
||||
"CHEVROLET_BOLT_EUV",
|
||||
"CHEVROLET_BOLT_CC",
|
||||
"CHEVROLET_BOLT_ACC_2022_2023",
|
||||
"CHEVROLET_BOLT_CC_2022_2023",
|
||||
"CHEVROLET_BOLT_CC_2019_2021",
|
||||
"CHEVROLET_BOLT_CC_2017",
|
||||
}
|
||||
if (params.get("CarModel", encoding='utf-8') or "") in bolt_models:
|
||||
params.remove("CarModelName")
|
||||
params_cache.remove("CarModelName")
|
||||
|
||||
with open(bolt_fingerprint_migration_flag_file, "w") as f:
|
||||
f.write(migration_branch or "unknown")
|
||||
|
||||
# One-time migration to align FrogPilot defaults after install
|
||||
frogpilot_migration_flag_file = "/data/media/0/frogpilot_migrated.flag"
|
||||
if not os.path.exists(frogpilot_migration_flag_file):
|
||||
|
||||
@@ -36,6 +36,19 @@ OVERLAY_INIT = Path(os.path.join(BASEDIR, ".overlay_init"))
|
||||
|
||||
DAYS_NO_CONNECTIVITY_MAX = 14 # do not allow to engage after this many days
|
||||
DAYS_NO_CONNECTIVITY_PROMPT = 10 # send an offroad prompt after this many days
|
||||
MIGRATED_TARGET_BRANCH = "StarPilot"
|
||||
MIGRATION_DONE_FILE = "/data/starpilot_branch_migrated"
|
||||
MIGRATION_SOURCE_BRANCH_FILE = "/data/media/0/starpilot_source_branch"
|
||||
MIGRATION_EXCLUDED_BRANCHES = {"Dom"}
|
||||
MIGRATION_SOURCE_BRANCHES = {
|
||||
"TorqueTune",
|
||||
"TorquePedal",
|
||||
"Kaofui",
|
||||
"Red-Kao",
|
||||
"TotallyTune",
|
||||
"StarPilot-2017",
|
||||
"TRX",
|
||||
}
|
||||
|
||||
class UserRequest:
|
||||
NONE = 0
|
||||
@@ -280,6 +293,7 @@ class Updater:
|
||||
self.params = Params()
|
||||
self.branches = defaultdict(str)
|
||||
self._has_internet: bool = False
|
||||
self._migrate_target_branch()
|
||||
|
||||
@property
|
||||
def has_internet(self) -> bool:
|
||||
@@ -292,6 +306,31 @@ class Updater:
|
||||
b = self.get_branch(BASEDIR)
|
||||
return b
|
||||
|
||||
def _migrate_target_branch(self) -> None:
|
||||
target_branch: str | None = self.params.get("UpdaterTargetBranch", encoding='utf-8')
|
||||
current_branch = self.get_branch(BASEDIR)
|
||||
if current_branch in MIGRATION_EXCLUDED_BRANCHES or target_branch in MIGRATION_EXCLUDED_BRANCHES:
|
||||
cloudlog.info(f"skipping StarPilot branch migration on excluded branch: current={current_branch}, target={target_branch}")
|
||||
return
|
||||
if current_branch not in MIGRATION_SOURCE_BRANCHES and target_branch not in MIGRATION_SOURCE_BRANCHES:
|
||||
cloudlog.info(f"skipping StarPilot branch migration on unmanaged branch: current={current_branch}, target={target_branch}")
|
||||
return
|
||||
|
||||
if current_branch != MIGRATED_TARGET_BRANCH:
|
||||
try:
|
||||
Path(MIGRATION_SOURCE_BRANCH_FILE).write_text(current_branch, encoding='utf-8')
|
||||
except OSError:
|
||||
cloudlog.exception(f"failed to persist source branch for migration: {MIGRATION_SOURCE_BRANCH_FILE}")
|
||||
|
||||
if target_branch != MIGRATED_TARGET_BRANCH or current_branch != MIGRATED_TARGET_BRANCH:
|
||||
self.params.put("UpdaterTargetBranch", MIGRATED_TARGET_BRANCH)
|
||||
cloudlog.info(f"migrated updater target branch to {MIGRATED_TARGET_BRANCH} from target={target_branch}, current={current_branch}")
|
||||
|
||||
try:
|
||||
Path(MIGRATION_DONE_FILE).touch()
|
||||
except OSError:
|
||||
cloudlog.exception(f"failed to write migration flag file: {MIGRATION_DONE_FILE}")
|
||||
|
||||
@property
|
||||
def update_ready(self) -> bool:
|
||||
consistent_file = Path(os.path.join(FINALIZED, ".overlay_consistent"))
|
||||
|
||||
Reference in New Issue
Block a user