Skip to content

Latest commit

 

History

History
240 lines (213 loc) · 4.61 KB

File metadata and controls

240 lines (213 loc) · 4.61 KB

Protocol Message Schema

All messages are JSON objects with a type field used for dispatch.


Watch → Server (WebSocket /ws/watch/{watch_id})

hello

Sent immediately after WebSocket connection is established.

{
  "type": "hello",
  "watch_id": "watch_01",
  "court_id": "court_01",
  "token": "padel-secret-token-change-me",
  "firmware_version": "1.0.0"
}

watch_event

Sent for every scoring action. event_id + seq together guarantee dedup.

{
  "type": "watch_event",
  "event_id": "watch_01-1700000000000-42",
  "seq": 42,
  "watch_id": "watch_01",
  "court_id": "court_01",
  "action": "point_a",
  "timestamp_ms": 1700000000000,
  "battery_pct": 85,
  "rssi": -65
}

Valid actions:

action meaning
point_a Point for team/side A
point_b Point for team/side B
undo Undo last scoring action
reset_game Reset current game to 0-0
reset_match Full match reset
timer_start Start match timer
timer_pause Pause match timer
timer_toggle Toggle timer start/pause

heartbeat (watch → server)

{
  "type": "heartbeat",
  "watch_id": "watch_01",
  "timestamp_ms": 1700000000000,
  "battery_pct": 85,
  "rssi": -65
}

Server → Watch

hello_ack

{
  "type": "hello_ack",
  "status": "ok",
  "court_id": "court_01",
  "message": "Connected"
}

ack

Sent for every received watch_event.

{
  "type": "ack",
  "event_id": "watch_01-1700000000000-42",
  "seq": 42,
  "status": "applied",
  "message": ""
}

status values:

  • applied — event was processed and score updated
  • duplicate — event_id already seen; ignored safely
  • no_match — no active match on this court
  • error — processing error (details in message)

state_update (server → watch)

Pushed after every score change on the watch's court.

{
  "type": "state_update",
  "court_id": "court_01",
  "score": {
    "game_score_a": "30",
    "game_score_b": "15",
    "games_a": 2,
    "games_b": 1,
    "sets_a": 1,
    "sets_b": 0,
    "completed_sets": [[6,4]],
    "status": "playing",
    "timer_seconds": 1234,
    "winner": null
  }
}

Display → Server (WebSocket /ws/display/{display_id})

hello

{
  "type": "hello",
  "display_id": "display_01",
  "court_id": "court_01",
  "token": "padel-secret-token-change-me"
}

heartbeat (display → server)

{
  "type": "heartbeat",
  "display_id": "display_01",
  "timestamp_ms": 1700000000000
}

Server → Display

hello_ack

{
  "type": "hello_ack",
  "status": "ok",
  "court_id": "court_01"
}

state_update (server → display)

Full match state pushed whenever anything changes.

{
  "type": "state_update",
  "court_id": "court_01",
  "court_name": "Court 1",
  "match": {
    "id": 1,
    "team_a": "Alice / Bob",
    "team_b": "Charlie / Dave",
    "game_score_a": "30",
    "game_score_b": "15",
    "games_a": 2,
    "games_b": 1,
    "sets_a": 1,
    "sets_b": 0,
    "completed_sets": [[6,4]],
    "status": "playing",
    "timer_seconds": 1234,
    "winner": null,
    "advantage": null
  }
}

no_match

Sent when a court has no active match.

{
  "type": "no_match",
  "court_id": "court_01",
  "court_name": "Court 1"
}

media_sync

Sent after connection and whenever media assignments change for this display.

{
  "type": "media_sync",
  "items": [
    {
      "id": 1,
      "filename": "ad_sponsor.jpg",
      "media_type": "image",
      "hash": "sha256:abc123...",
      "duration": 5.0,
      "order": 0
    },
    {
      "id": 2,
      "filename": "promo_video.mp4",
      "media_type": "video",
      "hash": "sha256:def456...",
      "duration": 15.0,
      "order": 1
    }
  ],
  "download_base": "http://10.144.186.211:8000/api/media/files"
}

Admin → Server (WebSocket /ws/admin)

The admin WebSocket is receive-only from the client side. The server pushes admin_state updates every 2 seconds.

admin_state

{
  "type": "admin_state",
  "courts": [
    {
      "court_id": "court_01",
      "court_name": "Court 1",
      "match_id": 1,
      "team_a": "Alice / Bob",
      "team_b": "Charlie / Dave",
      "score_summary": "1-0 | 30-15",
      "status": "playing",
      "timer_seconds": 1234,
      "watch_online": true,
      "display_online": true,
      "watch_battery": 85,
      "last_event_ms": 1700000001234
    }
  ]
}