Skip to content

Granit.IoT Bundle Reference

The two meta-bundles ship the full Granit.IoT stack as single NuGet references — one for the cloud-agnostic core, one for the AWS bridge family. Teams can onboard IoT device management, telemetry ingestion, threshold alerts, background jobs, the audit timeline, the MCP bridge for AI assistants, and (optionally) the full AWS IoT Core bridge without hand-picking 18 packages.

Granit.Bundle.IoT — cloud-agnostic stack (12 packages)

Section titled “Granit.Bundle.IoT — cloud-agnostic stack (12 packages)”

Use Granit.Bundle.IoT when:

  • You want the full Ring 1 + Ring 2 + Ring 3 stack wired up with sensible defaults
  • You’re starting a new greenfield Granit application
  • You don’t need to cherry-pick a subset (e.g. ingestion without endpoints)

Use individual packages when:

  • You only need the domain (tests, shared libraries)
  • You want to swap the EF Core layer for a custom persistence adapter
  • You’re integrating with an alternative web framework that doesn’t use Minimal API
#PackageRingRole
1Granit.IoT1Domain, value objects, events, CQRS abstractions
2Granit.IoT.EntityFrameworkCore1IoTDbContext, EF Core configurations
3Granit.IoT.EntityFrameworkCore.Postgres1PostgreSQL migrations (BRIN, GIN, partitioning)
4Granit.IoT.Endpoints1Device CRUD + telemetry queries
5Granit.IoT.BackgroundJobs1Purge, heartbeat, partition maintenance
6Granit.IoT.Ingestion2Provider-agnostic ingestion pipeline
7Granit.IoT.Ingestion.Endpoints2POST /iot/ingest/{source} webhook
8Granit.IoT.Ingestion.Scaleway2Scaleway IoT Hub provider
9Granit.IoT.Wolverine2Wolverine handlers + threshold evaluation
10Granit.IoT.Notifications3Bridge to Granit.Notifications
11Granit.IoT.Timeline3Bridge to Granit.Timeline
12Granit.IoT.Mcp3Read-only [McpServerTool] wrappers for AI assistants
flowchart LR
  B["Granit.Bundle.IoT<br/>(meta-package)"]
  B --> R1["Ring 1<br/>5 packages"]
  B --> R2["Ring 2<br/>4 packages"]
  B --> R3["Ring 3<br/>3 bridges"]
  • Granit.IoT.Mqtt + Granit.IoT.Mqtt.Mqttnet — add only if you need to consume from a non-Scaleway MQTT broker. See MQTT transport.
  • Granit.IoT.EntityFrameworkCore.Timescale — opt-in TimescaleDB backend. See Time-series storage.
  • Granit.IoT.Ingestion.Aws — AWS-native ingestion provider (SNS / Direct / API Gateway). Not bundled in Granit.Bundle.IoT.Aws (which covers the device-binding side); add it explicitly with dotnet add package Granit.IoT.Ingestion.Aws when you want AWS-shaped telemetry instead of (or alongside) the Scaleway webhook.
  • Granit.IoT.Aws family (6 packages — provisioning, shadow, jobs, JITP) — use Granit.Bundle.IoT.Aws on top.
Terminal window
dotnet add package Granit.Bundle.IoT

This single reference transitively pulls in all 12 bundled packages. No dependency conflicts — every package in the bundle targets the same Granit.* framework version pinned in Directory.Packages.props.

using Granit.Bundle.IoT;
builder.Services
.AddGranit(builder.Configuration)
.AddIoT();
app.MapGranitIoTEndpoints(); // /iot/devices + /iot/telemetry
app.MapGranitIoTIngestionEndpoints(); // /iot/ingest/{source}

AddIoT() enumerates the 11 active modules in topological order (Granit.IoT.EntityFrameworkCore.Postgres ships as helpers only, so it has no module class to register). Actual DI registration is driven by each module’s [DependsOn(...)] graph — the bundle’s enumeration is just a complete list, so dependency order is never a concern.

After AddIoT():

  • Device CRUD endpoints at /iot/devices (permissions, FluentValidation, OpenAPI)
  • Telemetry query endpoints at /iot/telemetry/{deviceId}
  • Scaleway webhook at /iot/ingest/scaleway (HMAC + Redis dedup + Wolverine outbox)
  • Three recurring background jobs (purge, heartbeat, partition maintenance)
  • Two notification types (threshold alert + device offline) auto-registered
  • Device lifecycle → timeline audit chatter
  • Four read-only MCP tools (iot_list_devices, iot_get_device, iot_query_telemetry, iot_get_latest_readings) — see MCP bridge
  • OpenTelemetry metrics for every stage (see Operations — Observability)

→ Already wired? Walk through it end-to-end on Getting started.

If the bundle is “too much,” register only what you need — each module’s DI extension is public:

builder.Services
.AddGranitIoT() // domain only
.AddGranitIoTEntityFrameworkCore() // persistence
.AddGranitIoTEndpoints(); // CRUD API
// skip ingestion / wolverine / jobs / bridges

The module system enforces ring discipline — you can’t accidentally register a Ring 3 bridge without its Ring 2 producer. Architecture tests catch violations at build time.

Granit.Bundle.IoT.Aws — AWS IoT Core bridge (6 packages)

Section titled “Granit.Bundle.IoT.Aws — AWS IoT Core bridge (6 packages)”

The opt-in companion bundle for hosts targeting AWS IoT Core. Add on top of Granit.Bundle.IoT — the core stack stays cloud-agnostic.

#PackageRole
1Granit.IoT.AwsCompanion AwsThingBinding, ThingName VO, IAwsIoTCredentialProvider
2Granit.IoT.Aws.EntityFrameworkCoreIsolated AwsBindingDbContext (iotaws_* schema)
3Granit.IoT.Aws.ProvisioningIAmazonIoT + Secrets Manager, idempotent provisioning saga
4Granit.IoT.Aws.ShadowDevice Shadow sync (reported push + delta polling)
5Granit.IoT.Aws.JobsIDeviceCommandDispatcher backed by AWS IoT Jobs
6Granit.IoT.Aws.FleetProvisioningJITP endpoints + claim cert rotation
Terminal window
dotnet add package Granit.Bundle.IoT.Aws
builder.Services
.AddGranit(builder.Configuration)
.AddIoT() // cloud-agnostic core
.AddGranitBundleIoTAws(o => o.UseNpgsql(connectionString)); // AWS bridge family

Full deep dive: AWS IoT Core bridge.

The bundles track the Granit.IoT release cycle. Pre-release (pre-v1.0.0), breaking changes land in minor versions; post-v1.0.0, SemVer applies strictly. The current compatibility matrix lives on the releases page — that’s the authoritative source for the Granit.IoT ↔ Granit framework ↔ .NET ↔ EF Core matrix.