feat: integrate cabin CAN and verified dynamic seat modes
This commit is contained in:
@@ -27,7 +27,14 @@ SEAT_MOTION_CAPABILITIES = {
|
||||
SEAT_RELATIVE_PHYSICAL_PARAMETERS = {"distance_mm", "angle_delta_deg"}
|
||||
SAVE_PRESET_CAPABILITY = "seat.save_posture_preset"
|
||||
APPLY_PRESET_CAPABILITY = "seat.apply_posture_preset"
|
||||
DYNAMIC_MODE_CAPABILITY = "seat.start_dynamic_mode"
|
||||
DYNAMIC_MODE_STOP_CAPABILITY = "seat.stop_dynamic_mode"
|
||||
DYNAMIC_MODE_MAX_RUNTIME_MS = 600_000
|
||||
HEX_COLOR = re.compile(r"^#[0-9A-Fa-f]{6}$")
|
||||
NATIVE_CAN_ONLY_CAPABILITIES = {
|
||||
"climate.set_control_mode",
|
||||
"roof.set_shade_motion",
|
||||
}
|
||||
|
||||
|
||||
class ModelPlanAdapter:
|
||||
@@ -69,7 +76,7 @@ class ModelPlanAdapter:
|
||||
)
|
||||
continue
|
||||
|
||||
domain, availability, capability = registered
|
||||
domain, domain_availability, capability = registered
|
||||
parameters = {
|
||||
str(item["name"]): item.get("value")
|
||||
for item in request.get("parameters", [])
|
||||
@@ -93,7 +100,26 @@ class ModelPlanAdapter:
|
||||
)
|
||||
continue
|
||||
|
||||
if availability != "executable":
|
||||
availability = (
|
||||
"native_can"
|
||||
if capability_name in NATIVE_CAN_ONLY_CAPABILITIES
|
||||
else domain_availability
|
||||
)
|
||||
native_only_request = (
|
||||
domain == "seat"
|
||||
and capability_name in SEAT_CAPABILITIES
|
||||
and (
|
||||
request.get("target_scope") in {"left_rear", "right_rear"}
|
||||
or parameters.get("level") in {4, 5}
|
||||
)
|
||||
) or (
|
||||
capability_name == "climate.set_outlet_mode"
|
||||
and (
|
||||
request.get("target_scope") == "vehicle"
|
||||
or parameters.get("mode") not in {"face", "feet"}
|
||||
)
|
||||
)
|
||||
if availability != "executable" or native_only_request:
|
||||
values = [value for value in parameters.values() if value is not None]
|
||||
deferred.append(
|
||||
{
|
||||
@@ -104,6 +130,11 @@ class ModelPlanAdapter:
|
||||
"requested_value": values[0] if len(values) == 1 else None,
|
||||
"parameters": parameters,
|
||||
"reason": request["reason"],
|
||||
"execution_backend": (
|
||||
"native_can"
|
||||
if availability == "native_can" or native_only_request
|
||||
else availability
|
||||
),
|
||||
}
|
||||
)
|
||||
continue
|
||||
@@ -182,6 +213,20 @@ class ModelPlanAdapter:
|
||||
}
|
||||
)
|
||||
continue
|
||||
if capability_name == DYNAMIC_MODE_STOP_CAPABILITY:
|
||||
dynamic_action = self._dynamic_mode_stop_action(
|
||||
index, request, parameters, ambiguities
|
||||
)
|
||||
if dynamic_action is not None:
|
||||
actions.append(dynamic_action)
|
||||
continue
|
||||
if capability_name == DYNAMIC_MODE_CAPABILITY:
|
||||
dynamic_action = self._dynamic_mode_action(
|
||||
index, request, parameters, ambiguities
|
||||
)
|
||||
if dynamic_action is not None:
|
||||
actions.append(dynamic_action)
|
||||
continue
|
||||
action = self._seat_action(
|
||||
index, request, parameters, ambiguities, context, vehicle_profile
|
||||
)
|
||||
@@ -352,6 +397,79 @@ class ModelPlanAdapter:
|
||||
return None
|
||||
return {"target": target, "preset_name": preset_name.strip()}
|
||||
|
||||
@staticmethod
|
||||
def _dynamic_mode_action(
|
||||
index: int,
|
||||
request: dict[str, Any],
|
||||
parameters: dict[str, Any],
|
||||
ambiguities: list[dict[str, str]],
|
||||
) -> dict[str, Any] | None:
|
||||
target = request.get("target_scope")
|
||||
if target != "passenger":
|
||||
ambiguities.append(
|
||||
{
|
||||
"field": f"requests[{index}].target_scope",
|
||||
"question": "当前动态座椅模式仅控制副驾。",
|
||||
}
|
||||
)
|
||||
return None
|
||||
mode_id = parameters.get("mode_id")
|
||||
if (
|
||||
not isinstance(mode_id, (int, float))
|
||||
or isinstance(mode_id, bool)
|
||||
or not float(mode_id).is_integer()
|
||||
or int(mode_id) not in {1, 2}
|
||||
):
|
||||
ambiguities.append(
|
||||
{
|
||||
"field": f"requests[{index}].parameters.mode_id",
|
||||
"question": "动态座椅模式编号必须是 1(木马模式)或 2(动态摇篮)。",
|
||||
}
|
||||
)
|
||||
return None
|
||||
normalized_mode_id = int(mode_id)
|
||||
return {
|
||||
"action_type": "dynamic_mode",
|
||||
"target": target,
|
||||
"mode_id": normalized_mode_id,
|
||||
"mode_name": (
|
||||
"木马模式"
|
||||
if normalized_mode_id == 1
|
||||
else "动态摇篮模式"
|
||||
),
|
||||
"repeat": "until_stopped_or_timeout",
|
||||
"max_runtime_ms": DYNAMIC_MODE_MAX_RUNTIME_MS,
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def _dynamic_mode_stop_action(
|
||||
index: int,
|
||||
request: dict[str, Any],
|
||||
parameters: dict[str, Any],
|
||||
ambiguities: list[dict[str, str]],
|
||||
) -> dict[str, Any] | None:
|
||||
target = request.get("target_scope")
|
||||
if target != "passenger":
|
||||
ambiguities.append(
|
||||
{
|
||||
"field": f"requests[{index}].target_scope",
|
||||
"question": "当前动态座椅模式仅控制副驾。",
|
||||
}
|
||||
)
|
||||
return None
|
||||
if parameters:
|
||||
ambiguities.append(
|
||||
{
|
||||
"field": f"requests[{index}].parameters",
|
||||
"question": "停止动态座椅模式不接受额外参数。",
|
||||
}
|
||||
)
|
||||
return None
|
||||
return {
|
||||
"action_type": "dynamic_mode_stop",
|
||||
"target": target,
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def _find_preset(
|
||||
presets: list[dict[str, Any]],
|
||||
|
||||
Reference in New Issue
Block a user