Skip to content

Device Binding in sim-dashboard

Device binding is the process of associating a simulated e-ink device with your Inklet user account. Once bound, you can send commands to the device and see its display output in the dashboard.

Binding Method

Device pairing now uses NFC binding only. sim-hw writes an NFC v2 URI payload to the data directory on startup, simulating the physical device's NFC tag.

Claim code is retired

The 6-character claim-code pairing method and POST /api/devices/bind/code endpoint were retired with NFC v2. They permanently return 410 Gone. sim-dashboard no longer offers a claim-code binding option.

NFC Payload Binding

sim-hw writes the NFC v2 URI payload to {data-dir}/nfc-payload on startup:

inklet://bind?v=2&kid=<keyId>&hw=<hwId>&cv=<credentialVersion>&p=<proof>

How it works:

  1. sim-hw generates the NFC v2 payload on startup and writes it to {data-dir}/nfc-payload
  2. You copy the URI string from that file
  3. Paste it into the sim-dashboard binding dialog
  4. The backend verifies the proof and binds the device to your account

Step-by-Step Binding Guide

Step 1: Start sim-hw

Launch a simulated device in its own terminal:

python -m eink_hw --data-dir devices/kitchen

On startup, sim-hw will:

  • Register with AWS IoT Core (provisioning on first run)
  • Send a heartbeat to the backend, which creates the device record
  • Generate an NFC v2 payload and write it to devices/kitchen/nfc-payload
  • Push the framebuffer to sim-dashboard

You should see log output like:

INFO  Connected as inklet-a1b2c3d4
INFO  Sending heartbeat...
INFO  NFC v2 payload written to devices/kitchen/nfc-payload
INFO  Framebuffer pushed to sim-dashboard

Step 2: Read the NFC Payload

cat devices/kitchen/nfc-payload
# inklet://bind?v=2&kid=k1&hw=a1b2c3d4e5f60708090a0b0c0d0e0f10&cv=1&p=AAAAAAAAAAAAAAAA

Step 3: Bind the Device

In sim-dashboard (logged in at http://localhost:5173):

  1. Click the "Bind Device" button in the top-right of the dashboard
  2. In the dialog, select the NFC Payload tab
  3. Paste the full URI string (e.g. inklet://bind?v=2&kid=...)
  4. Click Bind

Step 4: Device Appears in Dashboard

After a successful bind:

  1. The backend sends a bound command to the device via MQTT
  2. sim-hw renders "Device bound successfully" on the display
  3. The device appears in your dashboard with a live e-ink preview
  4. The device can now receive text commands

Step 5: Send Commands

Click the device card to open its detail view. Use the text input to send content to the device.

curl -X POST http://localhost:4000/api/devices/{id}/cmd \
  -H "Authorization: Bearer {accessToken}" \
  -H "Content-Type: application/json" \
  -d '{"kind": "text", "text": "Hello from the API!"}'

Unbinding a Device

  1. Click the bound device to open its detail view
  2. Click "Unbind"
  3. Confirm
curl -X POST http://localhost:4000/api/devices/{id}/unbind \
  -H "Authorization: Bearer {accessToken}"

What happens after unbind:

  1. The backend sends an unbound command via MQTT
  2. sim-hw clears its display
  3. The device disappears from your dashboard's bound-device list
  4. The device can be re-bound by scanning the same NFC payload (the proof remains valid while cv is unchanged)

Device keeps running

Unbinding does not stop the simulated device. sim-hw keeps running and sending heartbeats. You can re-bind at any time using the NFC payload.


Binding Lifecycle Diagram

sim-hw starts
    ├── Heartbeat → Backend creates device record
    ├── NFC payload written to nfc-payload file
    │              User reads nfc-payload and pastes in sim-dashboard
    │                          │
    │              POST /api/devices/bind/nfc (NFC v2)
    │                          │
    │              Backend verifies proof → binds device
    │                          │
    ├── bound received → Display shows "Bound successfully"
    │              Device appears in dashboard
    │              User sends text commands
    │                          │
    ├── text received → Display renders content
    │              User clicks "Unbind"
    │                          │
    │              POST /api/devices/{id}/unbind
    │                          │
    └── unbound received → Display clears

Troubleshooting

"Device not found" on bind

  • The device must have sent at least one heartbeat before binding. Wait a few seconds after starting sim-hw.
  • Confirm the device has been registered in the factory console and has an NFC credential file generated.

"Invalid NFC credential" on bind

  • Make sure you pasted the complete inklet://bind?... URI without truncation.
  • Confirm sim-hw's NFC_MASTER_KEYS matches the backend configuration.
  • If the device's credential was revoked and reissued, the payload file is updated — re-read it.

"Device already bound" error

  • The device is bound to another user. Unbind it first, or log in with the account that owns it.

Display not updating after bind

  • Check the WebSocket connection in your browser's developer tools
  • Confirm the Fastify server is receiving framebuffer POST requests from sim-hw
  • Try refreshing the page