mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-09-18 13:33:53 +08:00
fingerprint
This commit is contained in:
@@ -335,12 +335,31 @@ function scheduleSyncInputs() {
|
||||
|
||||
function applySelectOptions(el, options) {
|
||||
el.innerHTML = ""
|
||||
const labelsByValue = new Map()
|
||||
for (const opt of options || []) {
|
||||
if (opt?.developer_only && !state.values[GALAXY_DEVELOPER_MODE_KEY]) continue
|
||||
const o = document.createElement("option")
|
||||
o.value = String(opt.value)
|
||||
o.textContent = opt.label
|
||||
el.appendChild(o)
|
||||
if (el.id === "ds-CarModel") {
|
||||
if (!labelsByValue.has(o.value)) labelsByValue.set(o.value, [])
|
||||
labelsByValue.get(o.value).push(o.textContent)
|
||||
}
|
||||
}
|
||||
|
||||
if (el.id === "ds-CarModel") {
|
||||
for (const [modelValue, labels] of labelsByValue) {
|
||||
if (labels.length < 2) continue
|
||||
const baseNames = labels.map(label => label.split(" (")[0].replace(/\s+\d{4}.*$/, "").trim())
|
||||
const baseName = baseNames.every(name => name === baseNames[0]) ? baseNames[0] : modelValue
|
||||
const placeholder = document.createElement("option")
|
||||
placeholder.value = modelValue
|
||||
placeholder.textContent = `${baseName} (variant not identified)`
|
||||
placeholder.dataset.fingerprintVariantPlaceholder = "1"
|
||||
const firstVariant = Array.from(el.options).find(option => option.value === modelValue)
|
||||
el.insertBefore(placeholder, firstVariant)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -354,14 +373,16 @@ function syncSelectValue(el, key) {
|
||||
if (key === "CarModel") {
|
||||
const targetLabel = toSelectValue(state.values.CarModelName)
|
||||
const options = Array.from(el.options)
|
||||
const matchingIndex = options.findIndex(opt => {
|
||||
if (opt.value !== targetValue) return false
|
||||
return !targetLabel || opt.textContent === targetLabel
|
||||
})
|
||||
const matchingIndex = targetLabel ? options.findIndex(opt => opt.value === targetValue && opt.textContent === targetLabel) : -1
|
||||
if (matchingIndex !== -1) {
|
||||
el.selectedIndex = matchingIndex
|
||||
return
|
||||
}
|
||||
const unspecifiedIndex = options.findIndex(opt => opt.value === targetValue && opt.dataset.fingerprintVariantPlaceholder === "1")
|
||||
if (unspecifiedIndex !== -1) {
|
||||
el.selectedIndex = unspecifiedIndex
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
el.value = targetValue
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from test_dashboard_stats import MODULE_DIR, _install_server_import_stubs
|
||||
from test_navigation_params import WritableFakeParams, _params_client, the_galaxy as api_server
|
||||
|
||||
|
||||
def _load_server_module():
|
||||
@@ -17,7 +18,68 @@ the_galaxy = _load_server_module()
|
||||
def test_galaxy_lists_tesla_hardware_specific_docs_for_manual_fingerprinting():
|
||||
tesla_models = the_galaxy._extract_fingerprint_models_for_make("tesla")
|
||||
|
||||
assert {"value": "TESLA_MODEL_S_PREAP", "label": "Tesla Model S (Pre-AP) 2012-14"} in tesla_models
|
||||
assert {"value": "TESLA_MODEL_S_HW1", "label": "Tesla Model S (with HW1) 2014-16"} in tesla_models
|
||||
assert {"value": "TESLA_MODEL_S_PREAP", "label": "Tesla Model S (with HW1) 2014-16"} not in tesla_models
|
||||
assert {"value": "TESLA_MODEL_3", "label": "Tesla Model 3 (with HW3) 2019-23"} in tesla_models
|
||||
assert {"value": "TESLA_MODEL_3", "label": "Tesla Model 3 (with HW4) 2024-26"} in tesla_models
|
||||
assert {"value": "TESLA_MODEL_Y", "label": "Tesla Model Y (with HW3) 2020-23"} in tesla_models
|
||||
assert {"value": "TESLA_MODEL_X", "label": "Tesla Model X (with HW4) 2024"} in tesla_models
|
||||
|
||||
catalog = the_galaxy._get_fingerprint_catalog()
|
||||
assert catalog["label_to_model"]["Tesla Model S (with HW1) 2014-16"] == "TESLA_MODEL_S_HW1"
|
||||
|
||||
|
||||
def test_galaxy_does_not_assign_a_regional_label_to_ambiguous_ev6_fingerprint():
|
||||
kia_models = the_galaxy._extract_fingerprint_models_for_make("kia")
|
||||
assert {"value": "KIA_EV6", "label": "Kia EV6 (Southeast Asia only) 2022-24"} in kia_models
|
||||
assert {"value": "KIA_EV6", "label": "Kia EV6 (with HDA II) 2022-24"} in kia_models
|
||||
|
||||
catalog = the_galaxy._get_fingerprint_catalog()
|
||||
assert catalog["model_to_label"]["KIA_EV6"] is None
|
||||
|
||||
|
||||
def test_manual_fingerprint_api_keeps_the_saved_value_and_label_consistent(monkeypatch):
|
||||
client, params = _params_client(monkeypatch, {}, "pc")
|
||||
monkeypatch.setattr(api_server, "_get_param_type_info", lambda: ({"CarModel"}, {"CarModel": str}))
|
||||
monkeypatch.setattr(api_server, "update_starpilot_toggles", lambda: None)
|
||||
|
||||
hw1_label = "Tesla Model S (with HW1) 2014-16"
|
||||
options = client.get("/api/fingerprints/models?make=Tesla").get_json()
|
||||
assert {"value": "TESLA_MODEL_S_HW1", "label": hw1_label} in options
|
||||
response = client.put("/api/params", json={"key": "CarModel", "value": "TESLA_MODEL_S_HW1", "label": hw1_label})
|
||||
assert response.status_code == 200
|
||||
assert params.values["CarModel"] == "TESLA_MODEL_S_HW1"
|
||||
assert params.values["CarModelName"] == hw1_label
|
||||
|
||||
response = client.put("/api/params", json={"key": "CarModel", "value": "TESLA_MODEL_S_PREAP", "label": hw1_label})
|
||||
assert response.status_code == 400
|
||||
assert params.values["CarModel"] == "TESLA_MODEL_S_HW1"
|
||||
assert params.values["CarModelName"] == hw1_label
|
||||
|
||||
preap_label = "Tesla Model S (Pre-AP) 2012-14"
|
||||
response = client.put("/api/params", json={"key": "CarModel", "value": "TESLA_MODEL_S_PREAP", "label": preap_label})
|
||||
assert response.status_code == 200
|
||||
assert params.values["CarModel"] == "TESLA_MODEL_S_PREAP"
|
||||
assert params.values["CarModelName"] == preap_label
|
||||
|
||||
response = client.put("/api/params", json={"key": "CarModel", "value": "KIA_EV6"})
|
||||
assert response.status_code == 200
|
||||
assert params.values["CarModel"] == "KIA_EV6"
|
||||
assert "CarModelName" not in params.values
|
||||
|
||||
hda_label = "Kia EV6 (with HDA II) 2022-24"
|
||||
response = client.put("/api/params", json={"key": "CarModel", "value": "KIA_EV6", "label": hda_label})
|
||||
assert response.status_code == 200
|
||||
assert params.values["CarModelName"] == hda_label
|
||||
|
||||
|
||||
def test_fingerprint_diagnostic_flags_a_stale_label_value_mismatch(monkeypatch):
|
||||
monkeypatch.setattr(the_galaxy, "params", WritableFakeParams({
|
||||
"CarModel": "TESLA_MODEL_S_PREAP",
|
||||
"CarModelName": "Tesla Model S (with HW1) 2014-16",
|
||||
}))
|
||||
text = the_galaxy._get_fingerprint_snapshot_text()
|
||||
assert "Mismatch" in text
|
||||
assert "TESLA_MODEL_S_PREAP" in text
|
||||
assert "reselect" in text.lower()
|
||||
|
||||
@@ -13,6 +13,7 @@ import sysconfig
|
||||
import tarfile
|
||||
|
||||
import io
|
||||
import tokenize
|
||||
from io import BytesIO
|
||||
from pathlib import Path
|
||||
|
||||
@@ -3283,7 +3284,13 @@ def _extract_fingerprint_models_for_make(make_key):
|
||||
except Exception:
|
||||
return []
|
||||
|
||||
content = re.sub(r'#[^\n]*', "", content)
|
||||
lines = content.splitlines(keepends=True)
|
||||
for token in tokenize.generate_tokens(io.StringIO(content).readline):
|
||||
if token.type == tokenize.COMMENT:
|
||||
line_index, start = token.start[0] - 1, token.start[1]
|
||||
end = token.end[1]
|
||||
lines[line_index] = lines[line_index][:start] + " " * (end - start) + lines[line_index][end:]
|
||||
content = "".join(lines)
|
||||
content = re.sub(r'footnotes=\[[^\]]*\],\s*', "", content)
|
||||
|
||||
models = []
|
||||
@@ -3327,6 +3334,7 @@ def _get_fingerprint_catalog():
|
||||
all_models = []
|
||||
seen_all = set()
|
||||
model_to_label = {}
|
||||
labels_by_model = {}
|
||||
model_to_make = {}
|
||||
label_to_model = {}
|
||||
|
||||
@@ -3340,6 +3348,7 @@ def _get_fingerprint_catalog():
|
||||
model_label = entry["label"]
|
||||
|
||||
model_to_label.setdefault(model_value, model_label)
|
||||
labels_by_model.setdefault(model_value, set()).add(model_label)
|
||||
model_to_make.setdefault(model_value, make_label)
|
||||
label_to_model.setdefault(model_label, model_value)
|
||||
|
||||
@@ -3356,6 +3365,10 @@ def _get_fingerprint_catalog():
|
||||
|
||||
all_models.sort(key=lambda entry: entry["label"].lower())
|
||||
|
||||
for model_value, labels in labels_by_model.items():
|
||||
if len(labels) > 1:
|
||||
model_to_label[model_value] = None
|
||||
|
||||
_fingerprint_catalog_cache = {
|
||||
"makes": make_options,
|
||||
"models_by_make": models_by_make,
|
||||
@@ -4286,6 +4299,12 @@ def _get_fingerprint_snapshot_text():
|
||||
model_value = str(params.get("CarModel", encoding="utf-8") or "").strip()
|
||||
|
||||
if model_name and model_value:
|
||||
catalog = _get_fingerprint_catalog()
|
||||
if model_value in catalog["model_to_make"] and not any(
|
||||
entry["value"] == model_value and entry["label"] == model_name
|
||||
for entry in catalog["all_models"]
|
||||
):
|
||||
return f"Mismatch: {model_name} vs {model_value}; reselect your vehicle"
|
||||
return f"{model_name} ({model_value})"
|
||||
if model_name:
|
||||
return model_name
|
||||
@@ -6588,6 +6607,13 @@ def setup(app):
|
||||
return jsonify({"error": "Car model cannot be empty."}), 400
|
||||
|
||||
catalog = _get_fingerprint_catalog()
|
||||
if selected_label_input:
|
||||
labelled_models = {
|
||||
entry["value"] for entry in catalog["all_models"]
|
||||
if entry["label"] == selected_label_input
|
||||
}
|
||||
if labelled_models and selected_model not in labelled_models:
|
||||
return jsonify({"error": "Vehicle label and model do not match; refresh and reselect your vehicle."}), 400
|
||||
if selected_label_input and any(
|
||||
entry["value"] == selected_model and entry["label"] == selected_label_input
|
||||
for entry in catalog["all_models"]
|
||||
|
||||
Reference in New Issue
Block a user