Skip to main content

Set up and test a DCM IoT device

Introduction

This tutorial walks you through setting up a test IoT device that communicates with the DCM (Device Control Management) backend over MQTT. By the end you will have:

  • a device registered with Raytio,
  • a catalog of purchasable items with prices, assigned to the device's slots,
  • a device certificate issued from a CSR (certificate signing request) generated on the device — the private key never leaves the device,
  • a local simulator connecting to the IoT platform over MQTT,
  • the device requesting and applying its authoritative config via config/request,
  • and verification that the backend is receiving telemetry and delivering config.

The tutorial uses a shower facility as the example: one device with three shower heads (slots), each selling 5, 10, and 15-minute shower sessions. This matches the simulator shipped in the DCM SDK. Replace the device key, item names, and prices with your own values throughout.

Steps that touch the Raytio backend can be performed either in the web client or via the API — use the toggle on each step to see your preferred flow. Your choice is remembered across steps. API requests use a bearer token; see the API documentation for authentication details.

Prerequisites

  • A Raytio account with DCM administrator access to your tenant.
  • The Raytio dcm-sdk repository checked out locally.
  • uv installed (the SDK uses it for Python environment management).
  • openssl available on the device (or test machine) for key and CSR generation.

You do not need AWS credentials or database access. Certificate issuance and device provisioning are handled by Raytio.

Identity reference

Before you begin, understand the identifiers that interact throughout this tutorial:

IdentifierWhat it isWhere it appears
Device IDUUID assigned by Raytio when the device is registeredMQTT topic segments, simulator config, API paths
Device keyHuman-readable short code you choose (e.g. SHOWER-001)Display, certificate CN, simulator logging
Topic prefixdcm/{tenant_id}/{device_id}All MQTT topics for the device
CertificateX.509 certificate issued by Raytio from your CSRDevice connection (mTLS)
Topic identity

MQTT topics must use the device ID (UUID) as the topic segment — not the device key. The backend extracts the tenant ID and device ID from the topic path. Topics using the device key will not match any device record and messages will be silently dropped. The config.json you download in Step 6 contains the correct values.

Step 1 — Register the device

In the web client, open the admin dashboard and navigate to Devices → All Devices, then create a new device:

FieldExample valuePurpose
Device keySHOWER-001Human-readable identity, unique within your tenant
Device nameTest Shower Unit - PoolsideFriendly label shown in the UI
Device typeSHOWERDetermines which config categories apply

The device is created with a PROVISIONING status. Copy the device ID (UUID) from the device list — you will need it in later steps.

Step 2 — Create the shower items and prices

Each shower duration a customer can buy is an item, with a price attached. Create three items and three prices:

Item keyItem nameItem typeAmountCurrencyBilling
SHOWER_5MIN5-Minute ShowerSERVICE2.00NZDOne-time
SHOWER_10MIN10-Minute ShowerSERVICE3.50NZDOne-time
SHOWER_15MIN15-Minute ShowerSERVICE5.00NZDOne-time

Each shower session is a one-time charge, so the billing recurrence is ONCE.

  1. Navigate to Items and create the three items above, marking each as purchasable with item type SERVICE.
  2. Navigate to Prices and create one price per item with the amount, currency, and one-time billing shown above.

Step 3 — Create the device slots

Each slot represents a physical shower head. Create three slots:

Slot numberSlot nameStatus
1Shower Head 1AVAILABLE
2Shower Head 2AVAILABLE
3Shower Head 3AVAILABLE

Leave the slot's item field empty. A slot's item field represents the currently active session — it is set when a customer starts a session and cleared when the session ends. The list of items a slot can sell is configured separately in the next step.

Navigate to Devices → All Devices, select your device, and open the Slots tab. Create the three slots above.

Step 4 — Assign items to each slot

Each slot advertises the items it can sell through its slot item catalog. This is what allows one shower head to offer 5, 10, and 15-minute sessions — the customer picks the duration at the point of purchase.

Add all three shower items to each slot with a display order:

ItemDisplay order
5-Minute Shower1
10-Minute Shower2
15-Minute Shower3

Repeat for all three slots (nine catalog entries in total). Display order controls how the device presents the options — shortest and cheapest first.

Adding or changing slot items automatically queues a config sync, so a connected device receives the updated catalog without manual intervention.

Select a slot in the Slots tab and open its Slot Items tab. Add the three items with their display order, then repeat for the other two slots.

Item vs item catalog

These two fields have different semantics and are easy to confuse:

  • Slot item (single, nullable) — the item for the currently active session on the slot. Set when a purchase begins, cleared when the timer ends.
  • Slot item catalog (list) — the static menu of items the slot is configured to sell. The device uses this list to present options to a customer, and the backend validates purchases against it.

Step 5 — Generate a key and CSR on the device

The device generates its own private key and a certificate signing request (CSR) locally. The private key never leaves the device — Raytio only ever sees the CSR.

On the device (or your test machine), run:

mkdir -p ~/dcm-shower-001 && cd ~/dcm-shower-001

openssl req -new -newkey rsa:2048 -nodes \
-keyout device.key \
-out device.csr \
-subj "/CN=SHOWER-001"

This produces two files:

FilePurpose
device.keyPrivate key — stays on the device, keep secret
device.csrCertificate signing request — uploaded to Raytio in the next step

Step 6 — Issue the device certificate

In the web client, navigate to Devices → All Devices, select your device row, and choose the Issue Device Certificate action. Paste the contents of device.csr (or upload the file) and click Issue Certificate.

On success, the dialog offers two downloads:

FileContents
device.pem.crtThe X.509 device certificate issued from your CSR
config.jsonConnection details: IoT endpoint, tenant ID, device ID, device key, topic prefix

Download both and transfer them to the device, alongside the device.key you generated in Step 5.

The issued certificate also appears in the device's Certificates tab, and the device status moves out of PROVISIONING.

Step 7 — Write the simulator config file

Create a YAML config file in the testbench/ directory of the dcm-sdk repository, using the values from config.json (or the certificate API response) and the paths to your local certificate and key files:

testbench/shower-001.yaml
tenant_id: <tenant_id from config.json>
device_id: <device_id from config.json>
device_key: SHOWER-001
endpoint: <endpoint from config.json>
cert_path: /home/you/dcm-shower-001/device.pem.crt
key_path: /home/you/dcm-shower-001/device.key
heartbeat_interval: 30

device_id is the UUID the simulator uses as the MQTT topic segment. device_key is used for display and logging only.

You do not need to list slots in the config — the simulator discovers its slots and their item catalogs from the backend on startup.

Step 8 — Run the simulator

From the root of the dcm-sdk repository, run the test bench in cloud mode:

uv run python -m testbench run \
--mode cloud \
--config testbench/shower-001.yaml \
--duration-seconds 300

The --mode cloud flag connects to the IoT platform over MQTT using your certificate. On startup, the simulator will:

  1. Connect using the X.509 certificate and private key.
  2. Publish DEVICE_ONLINE on events/operational.
  3. Subscribe to config/set.
  4. Publish config/request with sections: ["device", "slots", "categories", "attributes", "attribute_values"].
  5. Wait for the config/set response and apply the received config.

Watch for the config delivery confirmation in the output:

Requesting config from backend
Config received — active slots: slot_1, slot_2, slot_3 (config_source=server_config)

Each slot in the received config carries its items array — the catalog you configured in Step 4:

{
"slot_number": 1,
"item_id": null,
"items": [
{"item_id": "…", "item_key": "SHOWER_5MIN", "item_name": "5-Minute Shower", "display_order": 1},
{"item_id": "…", "item_key": "SHOWER_10MIN", "item_name": "10-Minute Shower", "display_order": 2},
{"item_id": "…", "item_key": "SHOWER_15MIN", "item_name": "15-Minute Shower", "display_order": 3}
]
}
config_source=fallback_config

If the output shows config_source=fallback_config, the backend did not respond to the config request within the timeout and the simulator fell back to locally generated slots. This means the end-to-end path is not working — see Troubleshooting below.

Step 9 — Verify the backend received messages

While the simulator is running (or after it has completed), confirm the backend processed the device messages.

Navigate to Devices → All Devices and select your device:

  • The device row shows an updated last seen timestamp after the first heartbeat.
  • The Events tab shows a DEVICE_ONLINE event, followed by HEARTBEAT events at the configured interval.
  • The Slots tab shows all three slots reporting AVAILABLE with no active item.

Troubleshooting

Config set never arrives (config_source=fallback_config)

  1. Device and tenant IDs match — Confirm tenant_id and device_id in your simulator YAML exactly match the values in the downloaded config.json. A mismatch produces a topic the backend does not recognise, and messages are silently dropped.

  2. Slots and items configured — The config response includes an empty slot list if Steps 3 and 4 were skipped. Check the Slots tab and each slot's Slot Items tab.

  3. Certificate is active — Check the device's Certificates tab in the web client and confirm the certificate status is ACTIVE. If you re-issued a certificate, make sure the device is using the matching device.pem.crt — a certificate and key from different issuance rounds will fail the TLS handshake.

For a complete walkthrough of config discovery, see Config Discovery — Troubleshooting.

The simulator cannot connect at all

  1. Endpoint — Confirm the endpoint value matches config.json exactly.
  2. Certificate and key paths — Confirm cert_path points to the downloaded device.pem.crt and key_path to the device.key generated in Step 5, and that both files are readable.
  3. Key pair mismatch — The certificate was issued from the CSR created with your private key. If you regenerated the key after issuing the certificate, generate a new CSR and issue a new certificate (Steps 5 and 6).

The device connects but no events appear

  1. Topic uses the device UUID — The MQTT topic must use the device ID (UUID), not the device key. Check the simulator config file.
  2. Device registered in your tenant — Confirm the device appears under All Devices and its device ID matches your config.

If the connection succeeds and the configuration is correct but events still do not appear, contact your Raytio administrator or support — the remaining failure modes are on the backend side.

Summary

You have set up a complete end-to-end test path:

  1. Registered a device through the web client (or API).
  2. Created purchasable shower items with prices.
  3. Created three slots representing the shower heads.
  4. Assigned the item catalog to each slot, so one shower head can sell 5, 10, and 15-minute sessions.
  5. Generated a private key and CSR on the device, and had Raytio issue a certificate from the CSR — without the private key ever leaving the device.
  6. Configured the simulator from the downloaded config.json and local certificate files.
  7. Ran the test bench in cloud mode; the simulator connected, published online, and discovered its slot and item config from the backend.
  8. Confirmed message delivery and config discovery through the web client (or API).

For the conceptual background on how config discovery works, including all MQTT topic payloads, see Config Discovery. For the overall device control architecture, commands, and event flow, see Device Control System.