添加NFC绑定红外设备方式,融合车端设备和扩展设备统一控制

This commit is contained in:
minghanchen
2026-09-01 11:04:59 +08:00
parent 6d75944c0f
commit ca26259e63
14 changed files with 3694 additions and 316 deletions
+75 -13
View File
@@ -1507,7 +1507,11 @@ class SeatDemoService:
merged.update(
{
"phase": "two_stage_complete",
"utterance": str(manifest["utterance"]),
"utterance": str(
preview.get("utterance")
if preview.get("orchestration_route") == "unified_can_infrared"
else manifest["utterance"]
),
"provider_requested": selected_provider,
"preview_request_id": preview_request_id,
"supplement_of": preview_request_id,
@@ -1574,7 +1578,24 @@ class SeatDemoService:
merged["phase_execution_reports"] = {
"local_rule": deepcopy(preview.get("execution_report")),
"cloud_supplement": deepcopy(supplement.get("execution_report")),
**deepcopy(preview.get("phase_execution_reports") or {}),
}
merged["operation_results"] = [
*deepcopy(preview.get("operation_results") or []),
*deepcopy(supplement.get("operation_results") or []),
]
if preview.get("orchestration_route") == "unified_can_infrared":
merged["orchestration_route"] = "unified_can_infrared"
for key in (
"infrared_actions",
"peripheral",
"control_transports",
):
merged[key] = deepcopy(preview.get(key))
merged["provider_used"] = (
f"{supplement.get('provider_used') or 'cloud_supplement'}"
"+infrared_local_rules"
)
if supplement.get("execution_report") is None:
merged["execution_report"] = deepcopy(preview.get("execution_report"))
successful = {"succeeded", "partially_succeeded", "no_action"}
@@ -2039,18 +2060,6 @@ class SeatDemoService:
"hardware mode refuses virtual or unverified vehicle actions: "
+ ", ".join(unsupported)
)
if parsed.get("actions"):
(
self.vehicle_mqtt_settings
if control_transport == WIRELESS_MQTT_TRANSPORT
else self.hardware_settings
).authorize(approval_token)
if parsed.get("native_can_actions"):
(
self.vehicle_mqtt_settings
if control_transport == WIRELESS_MQTT_TRANSPORT
else self.vehicle_can_settings
).authorize(approval_token)
if not parsed.get("actions") and not parsed.get("native_can_actions"):
raise HardwareSafetyError(
"hardware mode requires at least one verified seat or vehicle CAN operation"
@@ -2192,6 +2201,7 @@ class SeatDemoService:
simulation_fault=simulation_fault,
vehicle_profile=vehicle_profile,
control_transport=control_transport,
approval_token=approval_token,
on_commands_validated=on_commands_validated,
)
@@ -2467,6 +2477,13 @@ class SeatDemoService:
self._emit_validated_commands(result, on_commands_validated)
if hardware_request:
self._authorize_compiled_hardware_delivery(
parsed,
approval_token,
control_transport,
)
safety_started = time.perf_counter()
self._trace(
traces,
@@ -4162,6 +4179,34 @@ class SeatDemoService:
event["execution_report"] = None
callback(event)
def _authorize_compiled_hardware_delivery(
self,
parsed: dict[str, Any],
approval_token: str | None,
control_transport: str,
) -> None:
"""Authorize physical transports after commands are safe to display.
Parsing, schema validation and deterministic CAN compilation do not
transmit frames. Keeping transport readiness checks after the
``commands_validated`` callback lets every UI target show the same
parsed commands, while these gates still run before any executor can
open a CAN or MQTT transmission path.
"""
if parsed.get("actions"):
(
self.vehicle_mqtt_settings
if control_transport == WIRELESS_MQTT_TRANSPORT
else self.hardware_settings
).authorize(approval_token)
if parsed.get("native_can_actions"):
(
self.vehicle_mqtt_settings
if control_transport == WIRELESS_MQTT_TRANSPORT
else self.vehicle_can_settings
).authorize(approval_token)
def _process_orchestrated(
self,
utterance: str,
@@ -4178,6 +4223,7 @@ class SeatDemoService:
simulation_fault: str = "normal",
vehicle_profile: VehicleProfile | None = None,
control_transport: str = WIRED_CAN_TRANSPORT,
approval_token: str | None = None,
on_commands_validated: Callable[[dict[str, Any]], None] | None = None,
) -> dict[str, Any]:
"""Run isolated adapters under the selected physical-bus policy."""
@@ -4444,6 +4490,13 @@ class SeatDemoService:
self._emit_validated_commands(result, on_commands_validated)
if hardware_request:
self._authorize_compiled_hardware_delivery(
parsed,
approval_token,
control_transport,
)
self._trace(
traces,
request_id,
@@ -5478,6 +5531,15 @@ class SeatDemoService:
}
)
def persist_composed_result(self, result: dict[str, Any]) -> None:
"""Persist a validated result composed with a non-CAN control domain."""
request_id = str(result.get("request_id") or "")
if not MODE_EDITOR_REQUEST_ID_PATTERN.fullmatch(request_id):
raise ValueError("invalid composed request id")
result.setdefault("trace_events", [])
self._persist(result)
def _persist(self, result: dict[str, Any]) -> None:
request_dir = self.artifact_root / result["request_id"]
(request_dir / "functions").mkdir(parents=True, exist_ok=True)
File diff suppressed because it is too large Load Diff