R&D · Thiết bị chấm điểm · Bản test nhanh · 14/10/2026

API test tín hiệu xe — JSON/HTTP MỚI

Bản tin giữa thiết bị trên xe và server chấm điểm, dùng để test trước: JSON qua HTTP cho nhanh. Tên trường và nghĩa giữ giống Protocol tín hiệu xe, nên khi chuyển sang Protobuf/MQTT chỉ đổi lớp vận chuyển. Chưa có RTK.

1

Endpoint

POST /api/v1/devices/{serial}/events
     body     : 1 event hoặc mảng event
     response : các lệnh đang chờ cho xe (thay cho kênh downlink)

Trường chung của mọi event

{ "seq": 1024, "t": 1760420000123, "session_id": "S-001", "type": "..." }
TrườngÝ nghĩa
seqSố thứ tự tăng dần; server dựa vào đây để phát hiện mất bản tin
tThời điểm xảy ra tín hiệu (epoch ms), không phải lúc gửi
session_idnull khi xe đang ngoài phiên thi
typeio · obd · state · ack
2

Xe gửi lên

2.1 io — gửi ngay khi một tín hiệu thân xe đổi trạng thái

{ "seq": 1024, "t": 1760420000123, "session_id": "S-001",
  "type": "io", "signal": "brake", "value": 1 }
signalvalue = 1 nghĩa làDùng ở
ignitionKhoá điện ONBài 1
seatbeltĐã cài dây an toànBài 1, lỗi xuyên suốt
doorCửa đang mởLỗi xuyên suốt
handbrakeĐang kéo phanh tayBài 1, 3
brakeĐang đạp phanhBài 2, 5, 8, tình huống nguy hiểm
clutchĐang đạp cônBài 3, 9
reverseĐang gài số lùiBài 7, 10
left_ind / right_indXi-nhan đang nháy (bo thu tự lọc xung)Bài 1, 4, 11; cả hai = đèn khẩn cấp

2.2 obd — định kỳ ~5Hz

{ "seq": 1025, "t": 1760420000200, "session_id": "S-001",
  "type": "obd", "rpm": 850, "speed_kmh": 0, "valid": true }
⚠️ Khi xe không trả lời OBD thì gửi "valid": false, không gửi rpm: 0, để server không phạt chết máy oan.

2.3 state — snapshot 1Hz, đồng thời làm heartbeat

{ "seq": 1026, "t": 1760420001000, "session_id": "S-001",
  "type": "state",
  "io": { "ignition":1, "seatbelt":1, "door":0, "handbrake":0, "brake":0,
          "clutch":0, "reverse":0, "left_ind":0, "right_ind":0 },
  "vbat_mv": 12600, "tamper": 0 }

2.4 ack — xác nhận đã thực thi lệnh

{ "seq": 1030, "t": 1760420005321, "session_id": "S-001",
  "type": "ack", "cmd_id": 10, "ok": true }
✅ Với hazard_trigger, giá trị t trong ack là thời điểm xe thực sự phát cảnh báo, và server dùng nó làm mốc đo thời gian phản ứng.
✅ Để giảm số request, xe có thể gom event trong 200–500ms rồi gửi một lần dưới dạng mảng [ {...}, {...} ].
3

Server trả về — lệnh cho xe

{ "ack_seq": 1026,
  "commands": [
    { "cmd_id": 7,  "type": "session_open", "session_id": "S-001", "exam_id": "K-2026-10", "candidate_ref": "TS-0153" },
    { "cmd_id": 8,  "type": "lesson_mark", "lesson": 3, "enter": true },
    { "cmd_id": 9,  "type": "announce", "text_key": "LOI_CHET_MAY", "lesson": 3, "points": -5 },
    { "cmd_id": 10, "type": "hazard_trigger" },
    { "cmd_id": 11, "type": "session_close", "session_id": "S-001" }
  ] }
LệnhXe làm gì
session_openGắn session_id vào mọi event từ đây
lesson_markĐánh dấu vào/ra bài (tạm thời bấm từ phòng điều hành, vì chưa có RTK)
announcePhát loa theo text_key
hazard_triggerPhát tín hiệu tình huống nguy hiểm, ack kèm giờ thực thi
session_closeKết thúc phiên, các event sau có session_id = null
✅ Xe gửi ack cho mọi lệnh. Server gửi lại lệnh chưa được ack ở response kế tiếp.
4

Kịch bản test gợi ý — bài 1 (xuất phát)

  1. Server trả session_open
  2. Xe gửi lần lượt: io ignition=1 → io seatbelt=1 → io left_ind=1 → io handbrake=0
  3. Xe gửi obd với rpm và speed tăng dần
  4. Server kiểm tra thứ tự và khoảng thời gian giữa các bước, rồi trả announce