feat: return 200 for motor control actions

This commit is contained in:
xtkuang 2026-08-07 09:59:04 +08:00
parent bb8a69e2d0
commit c9005baf9a
3 changed files with 33 additions and 10 deletions

View File

@ -232,6 +232,21 @@ curl -X POST "http://${SERVER_IP}:8000/v1/motor/stop"
curl "http://${SERVER_IP}:8000/v1/motor/status"
```
`open`、`close`、`stop` 成功时均返回 HTTP `200 OK`,响应 JSON 包含
`"code": 200`、执行动作和当前电机状态。例如:
```json
{
"code": 200,
"accepted": true,
"action": "stop",
"state": "stopped"
}
```
实际响应还包含电机 ID、控制量、广播状态等字段。硬件未启用或状态冲突仍返回
HTTP `409`,CAN/USB 通讯失败仍返回 HTTP `503`。
`MOTOR_HARDWARE_ENABLED=true` 时,启动过程会自动 Enable。HTTP 只保留
`open`、`close`、`stop` 和 `status`,不提供 `enable`/`disable`。

View File

@ -74,6 +74,7 @@ def create_app(
def response_for(result: MotorStatus, action: str) -> dict[str, Any]:
return {
"code": status.HTTP_200_OK,
"accepted": True,
"action": action,
"transmission": "CAN frame transmitted; physical motor motion is not verified",
@ -128,7 +129,7 @@ def create_app(
@app.post(
"/v1/motor/open",
status_code=status.HTTP_202_ACCEPTED,
status_code=status.HTTP_200_OK,
dependencies=[Depends(authorize)],
)
async def open_motor(request: Request) -> dict[str, Any]:
@ -137,7 +138,7 @@ def create_app(
@app.post(
"/v1/motor/close",
status_code=status.HTTP_202_ACCEPTED,
status_code=status.HTTP_200_OK,
dependencies=[Depends(authorize)],
)
async def close_motor(request: Request) -> dict[str, Any]:
@ -146,7 +147,7 @@ def create_app(
@app.post(
"/v1/motor/stop",
status_code=status.HTTP_202_ACCEPTED,
status_code=status.HTTP_200_OK,
dependencies=[Depends(authorize)],
)
async def stop(request: Request) -> dict[str, Any]:

View File

@ -100,7 +100,8 @@ def test_http_open_and_close_can_switch_directions() -> None:
reopened = await client.post("/v1/motor/open")
stopped = await client.post("/v1/motor/stop")
assert opening.status_code == 202
assert opening.status_code == 200
assert opening.json()["code"] == 200
assert opening.json()["action"] == "open"
assert opening.json()["state"] == "opening"
assert opening.json()["control_raw"] == 400
@ -110,18 +111,21 @@ def test_http_open_and_close_can_switch_directions() -> None:
assert opening.json()["broadcast_frequency_hz"] == 10
assert still_opening.json()["state"] == "opening"
assert still_opening.json()["streaming"] is True
assert closing.status_code == 202
assert closing.status_code == 200
assert closing.json()["code"] == 200
assert closing.json()["action"] == "close"
assert closing.json()["state"] == "closing"
assert closing.json()["control_raw"] == -400
assert closing.json()["control_raw_by_motor"] == {"1": -400, "2": 400}
assert "not verified" in closing.json()["transmission"]
assert reopened.status_code == 202
assert reopened.status_code == 200
assert reopened.json()["code"] == 200
assert reopened.json()["action"] == "open"
assert reopened.json()["state"] == "opening"
assert reopened.json()["control_raw"] == 400
assert reopened.json()["control_raw_by_motor"] == {"1": 400, "2": -400}
assert stopped.status_code == 202
assert stopped.status_code == 200
assert stopped.json()["code"] == 200
assert stopped.json()["state"] == "stopped"
asyncio.run(scenario())
@ -139,9 +143,11 @@ def test_automatic_enable_and_motion_do_not_require_feedback_replies() -> None:
opening = await client.post("/v1/motor/open")
stopped = await client.post("/v1/motor/stop")
assert opening.status_code == 202
assert opening.status_code == 200
assert opening.json()["code"] == 200
assert opening.json()["streaming"] is True
assert stopped.status_code == 202
assert stopped.status_code == 200
assert stopped.json()["code"] == 200
assert stopped.json()["streaming"] is False
asyncio.run(scenario())
@ -165,7 +171,8 @@ def test_one_http_stop_sends_two_explicit_stop_rounds() -> None:
(frame.arbitration_id, frame.data.hex()) for frame in transport.frames[start:]
]
timeouts_s = transport.tx_queue_timeouts_s[start:]
assert stopped.status_code == 202
assert stopped.status_code == 200
assert stopped.json()["code"] == 200
assert stopped.json()["state"] == "stopped"
assert frames == [
(CONTROL_FRAME_ID, "0000000000000000"),