Skip to content

Device data and control contract

This page describes the boundary between your product application and the Dataplicity field agent. It is a device-side integration contract, not the public Gateway API.

The connected-product suite and its local broker remain beta-gated. Dataplicity does not currently publish a minimum agent version for this contract. Before a production rollout, verify the exact agent release on representative hardware, confirm that the loopback broker is present, and run the acceptance checks on this page. The organisation administrator must also confirm that Device Class UI and any class Software capability are enabled.

Discover support instead of guessing

Treat support as a capability check:

  1. Read the device's reported agent version in the OEM workspace.
  2. Confirm the class exposes UI Components.
  3. From the product process, connect to 127.0.0.1:18765.
  4. Post a test sample to a staging stream and require a successful response.
  5. Confirm the sample appears on both the OEM preview and a customer-scoped portal account.

An agent version string alone is not a sufficient capability signal. There is currently no published compatibility table or local discovery endpoint that guarantees broker support. Record the versions you qualify in your own release matrix.

Stream request

For a single binding, supported agents accept:

text
POST http://127.0.0.1:18765/v1/streams/{binding_id}
Content-Type: application/json

Use the stable Device Class stream ID as {binding_id}. A sample envelope is:

json
{
  "sequence": 1842,
  "timestamp_ms": 1787385600123,
  "body": { "value": 4.2 },
  "metadata": { "source": "cold-room-service" }
}

Field contract

FieldDevice responsibilityCurrent service behaviour
sequenceSend a non-negative counter that is useful for diagnostics. Persist it across process restart if continuity matters to your product.Accepted as an integer. It is not a published exactly-once or ordering guarantee.
timestamp_msSend UTC Unix epoch milliseconds from a clock you have validated.Used as sample time. If omitted, receipt time may be used. Clock-skew tolerance is not a published contract.
bodySend an object whose value matches the class stream type and unit.The object is delivered as the sample payload. Server-side coercion must not be relied upon as product validation.
metadataSend only non-secret diagnostic context.Optional object. Retention and queryability of arbitrary keys are not guaranteed.

The current class stream types are Metric, Boolean, Text, JSON, Timeseries, Video, Image, and Events. A product publisher must still define the schema inside body for its selected type. Dataplicity does not currently publish a general JSON Schema registry for arbitrary stream bodies.

Binding IDs are at most 128 characters in the current service. Keep them to letters, digits, dots, underscores, colons, and hyphens so the same ID can be used safely by data and control paths. An unknown stream binding is not a safe way to create schema dynamically: current ingest can treat it as live-only, but it has no declared type, unit, widget, or customer contract. Define the binding on the Device Class first.

Response and retry

The released publisher helper should remain the reference implementation. Where you implement your own client:

  • treat 202 Accepted as acceptance by the local broker, not proof that a customer has rendered the sample
  • correct 400 payload or path failures before retrying
  • treat 403 as a local-security failure: the broker accepts loopback clients only
  • retry 503 broker_not_ready and transient 500 enqueue_failed responses with capped exponential backoff and jitter
  • keep the sampling loop independent from the upload retry loop
  • avoid an unbounded in-process queue

The current local broker accepts JSON object requests up to 256 KiB. That is the complete request limit; there is no separate published metadata allowance. On success it returns 202 with the binding and sequence it queued. It returns 400 for an empty, oversized, malformed, non-object, or unsupported request, 403 for a non-loopback client, 503 while the disk buffer is unavailable, and 500 if enqueueing fails unexpectedly. These are current agent semantics, not a promise that every older agent release implements the same responses.

The cloud ingest service currently returns 201 with accepted sample metadata and a limits object, 400 for an invalid envelope, 403 for the wrong device identity, and 429 with Retry-After when a rate budget is exceeded. Those are cloud-side implementation details used by the agent; an application posting to the loopback broker must use the status contract shipped with its qualified agent release.

No public idempotency key is defined for ordinary stream samples. A sequence may replace an existing durable record with the same device, binding, and sequence in the current implementation, but publishers must not treat that as a durable exactly-once guarantee. Samples can be delayed across an offline period. Do not infer event order from arrival order; use the sample timestamp and your own domain identifier where ordering matters.

Rates, batches, and retention

The agent's current cloud policy reports its effective limits in the ingest response. Current service defaults include a maximum of 2,000 samples in one cloud batch and 360 cloud batches per hour per device. Per-channel sample budgets vary by plan, stream type, retention, and current service coverage. These values are operational defaults, not a customer contract, and may be configured or changed. Do not hard-code them into the product.

Use the returned policy and the organisation's current service limits as the authority. Dataplicity does not currently publish guaranteed throughput, maximum offline queue size, queue eviction order, delivery latency, or replay window for the loopback broker.

Class history settingMeaningBehaviour to design for
Live onlyLast-known value for current UIIntermediate samples may not remain queryable.
Keep historyRecorded samples subject to plan retention and rate limitsHistory is finite and is not an archival system of record.

The Device Class setting is authoritative. A publisher-supplied storageProfile cannot turn a live-only stream into durable history. Unknown bindings are treated as live-only by the current service. JSON event streams are handled as durable history by the current implementation, but retention still follows the organisation's applicable service policy.

Offline, restart, and stale behaviour

Your product must define:

  • expected publish cadence
  • how long a last value remains operationally fresh
  • what the UI says before the first sample
  • what happens when the application restarts
  • whether domain events can be reconstructed after power loss

The agent performs cloud authentication, buffering, and retry. Dataplicity does not publish a guaranteed offline buffer duration or byte capacity.

The current agent stores accepted samples in a SQLite queue under its persistent state directory. Its default cap is 20,000 queued rows and its current upload batch cap is 2,000 rows. When the queue exceeds its configured row limit, it discards oldest volatile rows first, then oldest durable rows if necessary. The queue normally survives an agent process restart and a device reboot when the agent state directory remains intact; it does not survive deletion, corruption, reimaging, or loss of that storage. Both caps are configurable implementation defaults rather than contractual capacity.

If loss would be unsafe or commercially material, keep a durable device-side journal owned by your product and reconcile it using a domain event ID. Do not add a cloud credential to the publisher as a fallback.

A stale widget is a presentation outcome, not a device watchdog. Safety interlocks, local alarms, and fail-safe control remain in your product application even when the portal is unavailable.

Actions: requests from UI to device

An action definition configures a permitted request in UI Components. Current action kinds are trigger, list, and boolean. Creating the definition or placing a button only configures the UI and server-side allowlist.

The device application must independently:

  1. receive the agent-delivered oem.action message
  2. validate the binding and method again
  3. authorise the operation against local state
  4. apply timeouts, interlocks, and physical safety rules
  5. execute the operation
  6. publish result or state through a separate stream if the customer needs confirmation

Current server methods are get, on, off, set, and do; set carries a scalar string, number, or boolean. A request to an offline device is rejected by the current UI API, and an accepted request reports queued. That response does not mean the device executed the action. There is no published action idempotency, expiry, cancellation, or acknowledgement protocol. Design actions to be safe if a user retries, and publish an explicit result when proof matters.

In the current supporting agent, accepted actions enter an in-memory inbox of at most 256 requests. A container reads them with GET /v1/actions or GET /v1/actions/{binding_id}. The oldest request is discarded if the inbox is full, and pending requests do not survive an agent process restart or device reboot. A short duplicate-suppression window is an implementation detail, not an idempotency contract.

Settings: desired and reported state

A setting is a lasting desired value, not an action result. Current setting types are boolean, bounded number, and enum. The platform validates configured minimum, maximum, step, and enum choices before updating desired state. The backend can emit an oem.setting message to an online device, but the current published field agent does not expose a supported local settings consumer or handle that command. Device-side settings are therefore preview, not a production integration contract.

Do not tell customers that a settings widget changes device behaviour. Until a qualified agent release documents delivery and acknowledgement, use a supported idempotent action for a bounded change and publish the resulting state on a stream, or keep persistent configuration in your existing product-management path.

The service data model stores separate desired and reported values and timestamps, but that alone does not establish device delivery. There is no public contract for acknowledgement, compare-and-swap, setting revision IDs, offline setting queueing, conflict resolution, persistence, or automatic rollback. Treat those behaviours as unsupported unless your qualified release supplies a separately documented contract.

Production acceptance

Test streams, actions, and settings with:

  • broker absent, starting, and restarting
  • device offline and reconnecting
  • application restart and full power loss
  • duplicate and out-of-order domain events
  • invalid type, out-of-range number, unknown binding, and clock skew
  • rate limiting and a full local product queue
  • customer viewer, operator, and administrator roles
  • an action repeated after an ambiguous response
  • desired state that the device rejects or cannot apply