Get started with a device¶
Choose an SDK¶
Target |
SDK directory |
Use it for |
|---|---|---|
Python 3 |
|
reference integrations, Linux devices, and test automation |
Android/Kotlin |
|
Android-based terminals and controllers |
C11 |
|
embedded Linux, native controllers, and factory bootstrap software |
Emulator |
|
repeatable virtual-device and failure scenarios |
All SDKs use the same DDI-1 identity, HTTPS, MQTT, and OTA boundaries. Do not combine separate legacy device and Bazaar OTA clients. DDI is the sole terminal integration product; HawkBit compatibility is reached only through the DDI OTA prefix.
Provisioning origin and region¶
The platform serves two provisioning origins, one per region. A device is provisioned against the one its account’s region serves. The list and the transport port live in one place — Device connectivity — and are deliberately not repeated here, so there is no second copy to drift.
Each SDK names both as constants and supplies no default: fgai_mqtt.regions in
Python, FGAI_ORIGIN_TOKYO and FGAI_ORIGIN_SEOUL in C, DdiOrigins in
Android. Pass the origin where the device’s configuration is established — in
Python, persist(..., origin=...) — so it is recorded beside the certificates
and later OTA and certificate rotation read the same region back instead of
deciding it again.
An origin is accepted in both of its forms and they are one origin: the host
(things.flexgalaxy.ai) and the short name (tokyo, the form the platform
itself records on the device). Passing one where the other was recorded is not a
region change and is not refused.
Region is a property of the account: an operator binds it when the account is onboarded. It is not a per-device input, so no device, constructor, or provisioning request takes a region and nothing is homed per device. Choose the origin once per fleet, from the account’s region.
A device that is pointed at the other region’s origin is refused, and the refusal is terminal: the SDK surfaces a typed error and stops rather than backing off forever, and the recorded origin is left as it was. A configuration aimed at the other region’s origin is refused before the connection is attempted, so the device’s credential never reaches a broker that did not issue it. Moving a device between regions is an explicit re-provision, never a retry — see Errors and recovery for the per-SDK signal and the re-provision call.
Integration sequence¶
Configure the DDI HTTPS origin this device is enrolled against. It is the origin of the account’s region:
things.flexgalaxy.aifor Japan,things.ap-northeast-2.flexgalaxy.aifor Korea. The MQTT endpoint is not typed in: step 4 returns it asshared_config.mqtt_endpoint, and the SDK persists it beside the certificate and reads it back on reboot. Keep both configurable for customer-hosted deployments.Load the approved server trust anchors and the factory-issued bootstrap credential.
Generate the production private key on the device, preferably in a TPM or secure element.
Call
POST /ddi/v1/identify, thenPOST /ddi/v1/provisionwith a CSR.Persist the returned leaf certificate and CA chain atomically. Delete the bootstrap credential after provisioning succeeds.
Connect to MQTT 5 with mTLS, use the returned
thing_idas the MQTT identity, and publish only to the documented device topics.Register inbound callbacks before connecting, then publish telemetry and the device-owned CLIENT attribute snapshot.
Poll
/ddi/v1/ota/with the same device certificate when the product supports OTA.
Copy one of the repository’s minimal examples first, then adopt the robust example for production retry, persistence, and error handling. Never log the bootstrap bearer, enrollment token, private key, or raw authorization headers.
First operational session¶
The Python binding is the smallest executable reference. Install it from an authorized checkout:
python -m pip install ./sdks/python
After provisioning has persisted device.crt, device.key, ca.crt and the
broker endpoint the provisioning response carried, load the returned identity
and register inbound handlers before connect():
from fgai_mqtt import FGAIDeviceClient, ProvisionedIdentity
from fgai_mqtt._proto import command_pb2
# The SDK ships no default broker hostname: `load` reads back the endpoint
# persisted from the provisioning response's `shared_config.mqtt_endpoint`, and
# refuses when there is none rather than dialling an origin this device was
# never enrolled against.
identity = ProvisionedIdentity.load("certs")
device = FGAIDeviceClient(identity.device_config())
device.set_shared_attribute_callback(lambda key, value: apply_setting(key, value))
device.set_command_callback(
lambda command, respond: respond(
status=command_pb2.COMMAND_STATUS_SUCCEEDED,
result=b"ok",
error=None,
)
)
device.connect()
device.publish_telemetry({"temperature": 22.5}, tags={"site": "factory-a"})
device.report_client_attribute({"firmware_version": "1.0.0"})
apply_setting is application code: apply and persist the requested shared
attribute before returning. The SDK then acknowledges it. See
Device operations for the Android/Kotlin and C forms and
for the managed-runtime status of each operation.
Retry rules¶
Retry transport failures, 408, 429, and 5xx with exponential backoff and full jitter.
Honor
Retry-Afterwhen present.Do not retry other 4xx responses without correcting the request or identity.
Treat
DDI-1-403-IDENTITY-BLACKLISTEDas terminal.Reconnect MQTT with backoff and republish the client-attribute snapshot after a successful reconnect.
Manufacturing boundary¶
The SDK provisioning flow is not a replacement for the factory bootstrap
process. A bootstrap mini-OS may first read the hardware descriptor, enroll through
DDI, and use the DDI OTA route to obtain an assigned artifact. See the repository’s
docs/factory-bootstrap-flow.md for the complete sequence.