Skip to main content

Reference for Rust Device SDK

You can use the crate spotflow to integrate your Devices with the Spotflow IoT Platform.

Requirements

Compilation requirements:

We regularly test the compilation of the Device SDK on the following operating systems and CPU architectures:

  • Linux: x86, x64, ARMv7, AArch64
  • Windows: x64
  • macOS: x64, AArch64

You don't need any additional software to run the Device SDK on your Device.

Installation

Navigate to your project directory and run the following command to add the dependency on the spotflow crate to your project:

cargo add spotflow

Basic Usage

The following code connects the Device to the Platform and starts sending simulated sensor measurements. Add the dependencies on chrono and serde_json (for example, using cargo add chrono serde_json) to compile it.

You need to register to the Platform and set it up before you can use the code. See Get Started for more information on configuring the Platform, registering your Device, and viewing the received data. Don't forget to replace <Your Provisioning Token> with the actual Provisioning Token from the Platform.

get_started.rs
use serde_json::json;

use spotflow::{DeviceClientBuilder, MessageContext};

fn main() {
// Connect to the Platform (starts Device Provisioning if the Device is not already registered)
let provisioning_token = String::from("<Your Provisiniong Token>");

let client = DeviceClientBuilder::new(
Some(String::from("my-device")),
provisioning_token,
"spotflow.db",
)
.build()
.expect("Unable to build ingress connection");

// Create a Message context to send Messages to the Stream 'default' of the Stream Group 'default'
let message_context =
MessageContext::new(Some(String::from("default-stream-group")), Some(String::from("default-stream")));

// Your working code starts here. E.g. read data from your sensors and send it to the platform
for i in 0..60 {
// Example: Send sample data to the platform:

let payload = json!({
"timestamp": chrono::offset::Utc::now().to_rfc3339(),
"temperatureCelsius": 21.0 + (i as f64 * 0.05),
"humidityPercent": 50.0 + (i as f64 * 0.1),
})
.to_string();

client
.enqueue_message(&message_context, None, None, payload.clone().into_bytes())
.expect("Unable to send message");

println!("{payload}");

// Pause till next iteration
std::thread::sleep(std::time::Duration::from_secs(5));
}

// Your working code ends here.

// Wait for all the messages to be sent
loop {
let pending = client
.pending_messages_count()
.expect("Unable to obtain the number of pending messages");

if pending == 0 {
break;
}

println!("Waiting for {} more messages to be sent.", pending);
std::thread::sleep(std::time::Duration::from_secs(1));
}
}

Error Handling and Logging

The Device SDK uses anyhow::Result to return any errors that occur when calling a method. It uses the log crate to log any events happening in the background. You can use, for example, the env_logger crate to configure logging:

env_logger::Builder::from_env(
env_logger::Env::default()
.default_filter_or("sqlx=warn,ureq=warn,rumqtt=warn,ingress=info,spotflow=info,info"),
)
.init();

Backward Compatibility

The Rust interface of the Device SDK hasn't reached the version 1.0 yet. Therefore, we might introduce minor breaking changes as we improve the interface according to user feedback. However, we don't plan to remove any existing functionality.

Reference

The API reference is available on docs.rs. The most important types are DeviceClientBuilder and DeviceClient.