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 Methods

There are two ways to bind a device:

Method 1: Claim Code

The claim code method uses a 6-character alphanumeric code displayed on the device's e-ink screen.

How it works:

  1. When an unbound device starts up, it requests a claim code from the backend
  2. The backend generates a code (e.g., A3X9K2) and sends it to the device
  3. The device renders the code on its e-ink display
  4. You enter the code in the sim-dashboard to bind the device to your account

Method 2: NFC Payload

The NFC payload method uses the HMAC-signed hardware identifier that sim-hw generates.

How it works:

  1. sim-hw writes an NFC payload to {data-dir}/nfc-payload on startup
  2. The payload has the format inklet:1:{hwId}:{signature}
  3. You paste this string in the sim-dashboard binding dialog
  4. The backend verifies the HMAC signature and binds the device

Which method should I use?

For day-to-day simulator use, the claim code method is simpler since the code is displayed right on the simulated screen. The NFC payload method is useful for testing the NFC binding flow specifically or for automated testing scripts.


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
  • Request a claim code from the backend
  • Render the claim code on its simulated e-ink display
  • Push the framebuffer to sim-dashboard

You should see log output like:

INFO  Connected as inklet-a1b2c3d4
INFO  Sending heartbeat...
INFO  Received claim_code command: A3X9K2
INFO  Rendering claim code to display...
INFO  Framebuffer pushed to sim-dashboard

Step 2: View the Claim Code

The claim code is visible in two places:

  • sim-dashboard display --- If you are already viewing the device at its public URL (/device/{hwid}), the claim code renders on the simulated e-ink screen
  • sim-hw logs --- The claim code is printed in the terminal output

Step 3: Bind the Device

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

  1. Click the "Bind Device" button in the top-right area of the dashboard
  2. A dialog appears with two tabs: Claim Code and NFC Payload
  1. Select the Claim Code tab
  2. Enter the 6-character code from the device screen (e.g., A3X9K2)
  3. Click Bind
  1. Select the NFC Payload tab
  2. Read the payload from the sim-hw data directory:

    cat devices/kitchen/nfc-payload
    
  3. Paste the full payload string (e.g., inklet:1:a1b2c3d4-...:3f7a8b2c1d9e0f4a)

  4. Click Bind

Step 4: Device Appears in Dashboard

After successful binding:

  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 is now ready to receive text commands

Step 5: Send a Command

With the device bound, you can send text to its display:

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

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

The text renders on the simulated e-ink display with a realistic refresh animation.


Unbinding a Device

To unbind a device and return it to the pairing state:

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

What happens after unbinding:

  1. The backend sends an unbound command to the device via MQTT
  2. sim-hw receives the command and clears the display
  3. sim-hw automatically publishes a request_claim message
  4. The backend generates a new claim code and sends it to the device
  5. The device displays the new claim code, ready for re-pairing
  6. The device disappears from your dashboard's bound device list

Device Continues Running

Unbinding does not stop the simulated device. sim-hw continues running, sending heartbeats, and displaying its claim code. You can re-bind it at any time.


Binding Lifecycle Diagram

sim-hw starts
    ├── Heartbeat → Backend creates device record
    ├── request_claim → Backend generates code
    ├── claim_code received → Display shows "A3X9K2"
    │              User enters code in sim-dashboard
    │                          │
    │              POST /api/devices/bind/code
    │                          │
    │              Backend binds device to user
    │                          │
    ├── 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/{thing}/unbind
    │                          │
    ├── unbound received → Display clears
    └── request_claim → Cycle repeats

Troubleshooting

Claim code not appearing

  • Verify sim-hw is running and connected (check logs for Connected as inklet-...)
  • Ensure the backend is running on http://localhost:4000
  • Check that sim-dashboard's Fastify server is running on http://localhost:3001
  • Verify sim-hw is configured with --sim-url http://localhost:3001

"Device not found" error when binding

  • The device must have sent at least one heartbeat before binding. Wait a few seconds after starting sim-hw and try again.
  • Ensure the claim code has not expired. If it has, the device will automatically request a new one.

"Device already bound" error

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

Display not updating after binding

  • Check the WebSocket connection in browser dev tools
  • Verify the Fastify server is receiving framebuffer POSTs from sim-hw
  • Try refreshing the page