iot-device-bridge
This repository contains the components library and a running application in Rust for IoT MQTT messaging, Fleet Provisioning and Device Shadow.
IoT Bridge Design
The graphics shows the basic design, where the currently implemented components are indicated with continuous lines.
These components implement following functionality:
- basic configuration operations (configuration attributes stored in config.yaml file)
- basic message client operations:
- connect to cloud IoT (AWS IoT Core or alternate system)
- connect to device via MQTT (it can be extended to other messaging system like AMQP, DDS/ROS2)
- listen to incoming events
- subscribe to topic
- publish to topic
- fleet provisioning implementing AWS "Provisioning by Claim" workflow with CreateCertificateFromCsr
- basic device adapter operations
- mapping of device event topics to IoT topics
- filtering device incoming events
- standardize the message format to standard (cloudevents.io) with extensions
- device shadows (AWS)
device_shadow
- setting rules for events mapping
- setting rules for events filtering
iot_shadow
- certificate rotation request (by setting the parameter in the cloud shadow the IoT Bridge starts CSR based certificate renewal)
- cryptographic information about method and ciphers for payload encryption (tbi when applicable)
- cryptographic information about method and ciphers for payload anonymization (tbi when applicable)
For details see the IoT Bridge code documentation at artifacts download.
IoT Bridge Tasks Interaction
The IoT Bridge uses extensively the asynchronous multi-thread processing. The task interactions are summarized in the graphic below.
Remark: The device_interface
and iot_interface
are not explicit IoT Bridge tasks, but rather the corresponding connections to the corresponding messaging interfaces.
sequenceDiagram
participant DI as device_interface
participant DM as device_monitor_thread
participant DR as device_receiver_thread
participant DS as device_shadow_thread
participant IS as iot_shadow_thread
participant IT as iot_transmitter_thread
participant IR as iot_receiver_thread
participant IM as iot_monitor_thread
participant II as iot_interface
II-)IM: receive MQTT message
IM-)IR: receive event
IR->>IR: connector_aws::on_iot_event
alt event for IoT Shadow
IR-)IT: send response to IoT
IR-)IS: send shadow value
IS->>IS: trigger cert rotation
else event for Device Shadow
IR-)IT: send response to IoT
IR-)DS: send shadow value
DS->>DS: device_adapter::on_receive_device_shadow
end
DI-)DM: receive MQTT message
DM-)DR: receive event
DR->>DR: device_adapter::on_device_event
DR-)IT: send device message to IoT
IT-)II: send MQTT device message to IoT
Device Shadow Interaction
Based on the Reference Architecture in DEVICE SHADOWS - MQTT TOPICS.
This implementation differentiates between the Device State (an object as Rust struct
) and the Local Shadow (a copy of Device State as serde_json::Value
with additional info)
The sequence diagram below covers the main "positive" cases (i.e., no rejection).
Observation: UPDATE_DELTA is not send when the value of an attribute is set to null
.
sequenceDiagram
participant D as Device State
participant I as IoT Bridge
participant L as Shadow @ Device
participant R as Shadow @ Cloud
participant C as Cloud Application
Note right of L: Shadow Subscription
L-)R: SUBSCRIBE (UPDATE_ACCEPTED, UPDATE_REJECTED, UPDATE_DELTA)
Note right of L: Fleet Provisioning
I-)R: UPDATE[reported] (Initialize IoT Bridge / Connector State Shadow at Provisioning with Defaults)
I-)R: UPDATE[desired & reported] (Initialize Device State Shadow at Provisioning with Defaults)
R-)L: UPDATE_ACCEPTED (Device State)
L->>D: Transform & Store
Note right of L: IoT Bridge Start
I-)R: UPDATE[reported] (Send IoT Bridge / Connector State)
L-)R: GET (Get Device State Shadow at Start)
R-)L: GET_ACCEPTED
L->>D: Transform & Store
Note right of L: Change by Cloud Application (filtering / mapping)
C->>R: UPDATE[desired] (filter/map change)
R-)L: UPDATE_DELTA (Device State Shadow)
par Shadow@Device to Shadow@Cloud
L-)R: UPDATE[reported] (Device State Shadow)
and Shadow@Device to Device State
L-)D: Transform & Store
end
Note right of L: Certificate Rotation by Cloud Application
C->>R: UPDATE[desired] (cert rotation request)
R-)L: UPDATE_DELTA (IoT Bridge / Connector State Shadow)
par Shadow@Device to Shadow@Cloud
L-)R: UPDATE[reported] (IoT Bridge / Connector State Shadow)
and Shadow@Device to IoT Bridge / Connector
L-)I: Initiate Certificate Rotation
end
I->>I: Execute Certificate Rotation
IoT Bridge Configuration
The IoT Bridge configuration section device
is specific for the device and will not be discussed here.
The iot
section configures the connectivity to the IoT infrastructure -- below focusing on the AWS solutions.
All values below are placeholders only -- replace with your proprietary values.
IoT Connectivity
These elements can be left as defined if not specific requirements need to be considered.
shadow_name: iot_shadow
client_registration_status: INITIAL
ca_path: AmazonRootCA1.pem
The elements below are specific to the IoT connection of a group / a fleet of devices:
iot_topic_prefix: SPDIF/X320/16A8/
client_id: 16A8_99998
endpoint: ENDPOINTID-ats.iot.eu-central-1.amazonaws.com
port: 8883
Fleet Provisioning
For the AWS Fleet Provisioning the listed below elements of the configuration should be prepared and stored correspondingly, e.g., in the device-iot.config/certs
folder:
claim_cert_path: ClaimCertificate.pem
claim_priv_key_path: ClaimPrivateKey.pem
claim_pub_key_path: ClaimPubKey.pem
Additionally the Fleet Provisioning template is required and should be referenced (e.g., provisioning_template_name: iot-16A8-prov-templ
) and the corresponding provisioning policies and device policies defined. See AWS documentation for details.
The registration status client_registration_status: INITIAL
triggers the Fleet Provisioning. After successful registration the state changes to REGISTERED:thingname
The below listed client (device instance) specific elements will be generated during the Fleet Provisioning
client_cert_path: IotCertificate.pem
client_priv_key_path: IotPrivateKey.pem
client_pub_key_path: IotPubKey.pem