rust-iot

SKILL.md

IoT Development

Domain Constraints

Domain Rule Design Constraint Rust Implication
Unreliable network Offline-first Local buffering
Power constraints Efficient code Sleep modes, minimal alloc
Resource limits Small footprint no_std where needed
Security Encrypted comms TLS, signed firmware
Reliability Self-recovery Watchdog, error handling
OTA updates Safe upgrades Rollback capability

Critical Rules

  • Network can fail at any time — design offline-first with local queue and retry with backoff.
  • Minimize power consumption — use sleep modes and efficient algorithms for battery life.
  • All communication encrypted — physical access is possible, use TLS and signed messages.

Environment Comparison

Environment Stack Crates
Linux gateway tokio + std rumqttc, reqwest
MCU device embassy + no_std embedded-hal
Hybrid Split workloads Both

Key Crates

Purpose Crate
MQTT (std) rumqttc, paho-mqtt
Embedded embedded-hal, embassy
Async (std) tokio
Async (no_std) embassy
Logging (no_std) defmt
Logging (std) tracing

Design Patterns

Pattern Purpose Implementation
Pub/Sub Device comms MQTT topics
Edge compute Local processing Filter before upload
OTA updates Firmware upgrade Signed + rollback
Power mgmt Battery life Sleep + wake events
Store & forward Network reliability Local queue

MQTT Client Pattern

use rumqttc::{AsyncClient, MqttOptions, QoS};

async fn run_mqtt() -> anyhow::Result<()> {
    let mut options = MqttOptions::new("device-1", "broker.example.com", 1883);
    options.set_keep_alive(Duration::from_secs(30));

    let (client, mut eventloop) = AsyncClient::new(options, 10);

    // Subscribe to commands
    client.subscribe("devices/device-1/commands", QoS::AtLeastOnce).await?;

    // Publish telemetry
    tokio::spawn(async move {
        loop {
            let data = read_sensor().await;
            client.publish("devices/device-1/telemetry", QoS::AtLeastOnce, false, data).await.ok();
            tokio::time::sleep(Duration::from_secs(60)).await;
        }
    });

    // Process events with reconnection
    loop {
        match eventloop.poll().await {
            Ok(event) => handle_event(event).await,
            Err(e) => {
                tracing::error!("MQTT error: {}", e);
                tokio::time::sleep(Duration::from_secs(5)).await;
            }
        }
    }
}

Common Mistakes

Mistake Domain Violation Fix
No retry logic Lost data Exponential backoff
Always-on radio Battery drain Sleep between sends
Unencrypted MQTT Security risk TLS
No local buffer Network outage = data loss Persist locally
Weekly Installs
4
GitHub Stars
3
First Seen
Feb 9, 2026
Installed on
opencode4
gemini-cli4
github-copilot4
codex4
claude-code3
amp3