tpt-stratum

Rust

Federated environmental data mesh: IoT sensor nodes gossip observations over QUIC, validate against neighbours, and serve a live HTTP API. Pure-Rust embedded storage, Ed25519-signed readings, SSE streaming. Runs on a Raspberry Pi Zero. No C dependencies, no cloud required.

0 stars0 forks0 watchersApache License 2.0
embeddedenvironmental-monitoringgeospatialiotpeer-to-peerquicraspberry-pirustsensor-networkweather-station

Languages

Rust99.3%Dockerfile0.7%
README

tpt-stratum

A federated environmental data mesh — a peer-to-peer network of IoT sensor nodes that share, validate, and query geospatial environmental observations (temperature, humidity, pressure, and more).

Nodes gossip observations over QUIC, validate them against neighbours, store them locally, and expose an HTTP query API. The design is intentionally self-contained: no Kubernetes, no managed cloud, no C library dependencies. A Raspberry Pi Zero can run a full node.

Three commands to launch

# Install the binary
cargo install --path crates/tpt-stratum-node

# Initialise a new node (generates keypair + default config)
tpt-stratum init

# Start the node
tpt-stratum start

Or with Docker:

docker compose -f docker/docker-compose.yml up --build

What it does

  • Ingest — accepts observations from local sensors (HTTP JSON, Davis weather stations, Ecowitt gateways, BME280 I2C, MQTT) or over the network
  • Sign — every observation is Ed25519-signed by the originating node
  • Store — pure-Rust embedded storage engine (WAL + SSTable, no RocksDB)
  • Gossip — epidemic broadcast to a random fanout of peers over QUIC
  • Validate — plausibility bounds + spatial IDW + temporal z-score anomaly detection
  • Query — HTTP API for current conditions, time series, and real-time SSE streaming

Architecture

Sensor → Ingest Adapter → sign (Ed25519) → ObservationStore
                                                  ↓
                                          gossip broadcast (QUIC)
                                                  ↓
                                         neighbour nodes → validate
                                                  ↓
                                         HTTP API consumers

Configuration

Default config is written by tpt-stratum init to ./stratum.toml. Every key can be overridden by an environment variable prefixed TPT__:

[node]
keypair_path = "./stratum.key"
storage_path = "./data"

[network]
mesh_listen      = "0.0.0.0:9001"
heartbeat_listen = "0.0.0.0:9002"
api_listen       = "0.0.0.0:8080"
ingest_listen    = "0.0.0.0:8081"
initial_peers    = ["other-node.example.com:9001"]

[validation]
enabled             = true
plausibility_weight = 0.5
spatial_weight      = 0.3
temporal_weight     = 0.2

[db_limits]
max_age_days  = 30
disk_quota_mb = 0   # 0 = unlimited

[[sensors]]
adapter   = "http_json"   # accept JSON POSTs on ingest_listen
latitude  = 51.5074
longitude = -0.1278

Environment variable override syntax:

TPT__NETWORK__API_LISTEN=0.0.0.0:9090 tpt-stratum start

HTTP API

EndpointDescription
GET /healthLiveness probe → {"status":"ok"}
GET /now?lat=&lng=IDW-interpolated current conditions
GET /series?lat=&lng=&from=&to=&limit=&offset=Historical time series with pagination
GET /stream?north=&south=&east=&west=SSE real-time feed filtered by bounding box

See docs/QUICKSTART.md for worked examples.

CLI

tpt-stratum init     — generate keypair + default config
tpt-stratum start    — start the node
tpt-stratum keygen   — print a new keypair (does not persist)
tpt-stratum status   — show node status (placeholder)
tpt-stratum peers    — list connected peers (placeholder)

Global flags: --config, --data-dir, --verbose.

Workspace structure

Seven crates, each with a single responsibility:

CrateRole
tpt-stratum-coreDomain types, Ed25519 crypto, protobuf schema
tpt-stratum-storageCustom embedded storage engine (WAL + SSTable, pure Rust)
tpt-stratum-meshQUIC P2P gossip network (epidemic broadcast + backfill)
tpt-stratum-validatePluggable confidence scoring pipeline
tpt-stratum-apiAxum HTTP query API
tpt-stratum-ingestSensor adapters (HTTP JSON, Davis, Ecowitt, BME280, MQTT)
tpt-stratum-nodeBinary entry point, CLI, config

Build requirements

  • Rust 1.85+ stable (edition = "2024")
  • No C dependencies — pure Rust throughout
cargo build --release
cargo test
cargo clippy --all-targets --all-features

Extending the mesh

  • Custom adapter — implement IngestAdapter in tpt-stratum-ingest. See docs/ADAPTERS.md.
  • Custom validator — implement Validator in tpt-stratum-validate and add it to the Pipeline.
  • API client — any HTTP client works. The SSE stream is standard text/event-stream.

License

Apache 2.0 — see LICENSE.