Device attributes¶
Attributes are key/value facts attached to a thing — firmware_version,
polling_interval_seconds, fleet_tier, and so on. Every attribute lives in
exactly one of three buckets that differ in who may write it and whether it
syncs to the device. As a device integrator you work with two of the three.
The three buckets¶
Bucket |
Who writes |
Device sync |
Example keys |
|---|---|---|---|
CLIENT |
the device only |
device reports up; cloud reads |
|
SHARED |
the cloud AND the device |
both directions |
|
SERVER |
the cloud only |
never sent to the device |
tenant-side organization only |
Your device firmware touches CLIENT (facts it reports) and SHARED (config it receives and acknowledges). The SERVER bucket is cloud-side organization and never reaches the device — you can ignore it.
Keys are yours to define. A key must match ^[a-zA-Z_][a-zA-Z0-9_]{0,62}$; a
value can be a string, number, boolean, small object, or array.
CLIENT — report facts up¶
The device is the source of truth for CLIENT attributes. It reports them on connect and whenever they change; the cloud can read them but never writes them. CLIENT reporting rides the device’s existing reported-state channel — there is no separate wire message to construct.
If two reports for the same key arrive out of order, the platform keeps the one with the later device timestamp (last-writer-wins by device time), so a delayed or replayed report never overwrites a newer value.
Wire topics¶
CLIENT and SHARED use the following topics on your device’s own subtree (see Device MQTT topic access):
Topic |
Direction |
Carries |
|---|---|---|
|
device → cloud |
reported CLIENT attributes (reported-state wire) |
|
cloud → device |
a SHARED value to effect |
|
device → cloud |
acknowledgment of the effected value |
The frozen wire messages (DeviceAttributeSharedPush, DeviceAttributeSharedAck)
are defined in the DDI-1 contract. Use the SDK
below rather than encoding them by hand.
Python SDK¶
The device-side DDI SDK (SiriusVoyager/ddi, Python)
handles both directions for you. Construct a client, register a SHARED callback,
and report CLIENT attributes:
from fgai_mqtt import FGAIDeviceClient, DeviceConfig
client = FGAIDeviceClient(DeviceConfig(device_id="my-thing-id", ...))
# Receive SHARED-bucket pushes from the cloud. The SDK effects the value into a
# local shadow and publishes the ack for you — your callback just applies it.
def apply_shared(key, value):
print(f"cloud set {key} = {value}")
client.set_shared_attribute_callback(apply_shared)
client.connect()
# Report CLIENT-bucket facts up to the cloud.
client.report_client_attribute({"firmware_version": "8.4.2", "boot_count": 12})
# The last SHARED values the device received + effected:
print(client.shared_attribute_shadow)
Call |
Bucket |
What it does |
|---|---|---|
|
CLIENT |
report device-owned facts up |
|
SHARED |
register |
|
SHARED |
the device’s last-effected SHARED values ( |
The SDK always publishes the SHARED acknowledgment after your callback runs, so the cloud’s record of the effective value stays in step with the device — even if your callback raises.