wireband-edge 0.2.0

Lightweight Wire.Band client for IoT gateway hardware — Raspberry Pi, NVIDIA Jetson, industrial PCs
Documentation

wireband-edge

Lightweight Wire.Band client for IoT gateway hardware — Raspberry Pi, NVIDIA Jetson, industrial PCs.

Collects telemetry from MQTT, serial ports, BLE, Modbus, and CoAP, frames it with a 2-byte theta-symbol prefix, and flushes batches to the Wire.Band backend over HTTPS (rustls — no OpenSSL dependency).

Quick start

# MQTT gateway (default feature)
wireband-edge \
  --broker mqtt://localhost:1883 \
  --topics "sensors/#" \
  --backend https://ingest.wire.band \
  --api-key YOUR_API_KEY \
  --device-id factory-rpi4

Installation

cargo add wireband-edge
# All protocol connectors + agent
cargo add wireband-edge --features "mqtt,serial,ble,coap,modbus,agent"

Features

Feature Description
mqtt (default) MQTT connector via rumqttc
serial UART/RS-232/RS-485 via tokio-serial
ble Bluetooth LE GATT notifications via btleplug
modbus Modbus TCP register poller via tokio-modbus
coap CoAP UDP server for constrained sensors via coap-lite
agent Device twin, OTA updates, hardware watchdog
infer-onnx Edge inference via ONNX Runtime
infer-tflite Edge inference via TensorFlow Lite
python PyO3 bindings (built via maturin)

Library usage

use wireband_edge::{WireBandClient, ClientConfig};
use wireband_edge::mqtt::MqttConnector;

#[tokio::main]
async fn main() -> wireband_edge::Result<()> {
    let client = WireBandClient::new(ClientConfig {
        backend_url: "https://ingest.wire.band".into(),
        api_key:     Some("YOUR_API_KEY".into()),
        device_id:   "factory-rpi4".into(),
        ..Default::default()
    });
    client.start();

    MqttConnector::new("mqtt://localhost:1883")
        .run(client.clone(), &["sensors/#"])
        .await
}

Protocol connectors

BLE (Bluetooth Low Energy)

use wireband_edge::ble::BleConnector;
use std::time::Duration;

BleConnector::new("temp-sensor", "6e400003-b5a3-f393-e0a9-e50e24dcca9e")?
    .scan_duration(Duration::from_secs(10))
    .topic_prefix("factory/ble")
    .delta_threshold(0.01)
    .run(client)
    .await?;

Serial (UART / RS-232 / RS-485)

use wireband_edge::serial::SerialConnector;

SerialConnector::new("/dev/ttyUSB0", 115_200)
    .topic_prefix("factory/line1")
    .delta_threshold(0.01)
    .run(client)
    .await?;

CoAP (constrained sensors)

use wireband_edge::coap::CoapServer;

// Sensors PUT to coap://gateway-ip/sensors/zone-a/temp
CoapServer::new("0.0.0.0:5683")
    .topic_prefix("factory/coap")
    .run(client)
    .await?;

Modbus TCP

use wireband_edge::modbus::{ModbusPoller, RegisterDef};
use std::time::Duration;

ModbusPoller::new("192.168.1.100:502")
    .slave(1)
    .poll_interval(Duration::from_secs(5))
    .topic_prefix("factory/plc")
    .registers(vec![
        RegisterDef::new(0x0100, 1, "motor_rpm",   1.0),
        RegisterDef::new(0x0101, 1, "motor_temp",  0.1),  // 0.1 °C per LSB
        RegisterDef::new(0x0102, 2, "energy_kwh",  0.001),
    ])
    .run(client)
    .await?;

Agent (device twin, OTA, watchdog)

use wireband_edge::agent::{DeviceTwin, OtaManager, OtaUpdate, Watchdog};
use std::time::Duration;

// Device twin — sync reported/desired state
let twin = DeviceTwin::new("factory-rpi4");
twin.update_reported(serde_json::json!({"firmware": "1.2.3"})
    .as_object().unwrap().clone()).await;
twin.sync(&client).await;

// OTA firmware update
OtaManager::new("/tmp/ota-staging")
    .run(OtaUpdate {
        url:             "https://releases.example.com/fw-1.3.0.bin".into(),
        target_path:     "/usr/local/bin/sensor-daemon".into(),
        expected_sha256: Some("abc123...".into()),
        version:         "1.3.0".into(),
    }, &client)
    .await?;

// Watchdog — kicks /dev/watchdog + emits heartbeat
tokio::spawn(Watchdog::new(Duration::from_secs(30)).run(client.clone()));

Edge inference

ONNX Runtime

use wireband_edge::infer_onnx::OnnxInference;

let model = OnnxInference::from_file("anomaly_detector.onnx", "input", "output")?;

// In your sensor loop:
let scores = model.run(&sensor_readings, &[1, 16], "zone-a/anomaly", &client).await?;
if scores[0] > 0.85 {
    tracing::warn!("Anomaly detected: score={:.2}", scores[0]);
}

TensorFlow Lite

use wireband_edge::infer_tflite::TfliteInference;

let model = TfliteInference::from_file("anomaly.tflite")?;

let scores = model.run(&sensor_readings, "zone-a/anomaly", &client).await?;

Python extension

Install the Rust-backed Python extension via maturin:

pip install maturin
cd edge-rs
maturin develop --features python
from wireband_edge_rs import WireBandClient

client = WireBandClient(
    backend_url="https://ingest.wire.band",
    device_id="factory-rpi4",
    api_key="YOUR_API_KEY",
)
client.start()
client.buffer_event("sensors/temp", 0xFC62, '{"value": 23.5}')
print(client.stats())

Cross-compilation

Pre-built binaries for common targets are available on the GitHub releases page.

To cross-compile yourself:

cargo install cross
cargo build-rpi4   # aarch64 (RPi 4, Jetson)
cargo build-rpi3   # armv7 (RPi 3, Zero 2)
cargo build-rpi0   # arm (RPi Zero, RPi 1)
cargo build-x86    # x86_64 Linux

License

MIT