Build distributed edge computing systems with Microsoft Orleans virtual actors to control IoT hardware on Raspberry Pi devices with state persistence and cluster management.
Build distributed edge computing systems using Microsoft Orleans virtual actors to control IoT hardware on resource-constrained edge devices. This skill guides you through implementing remote LED control systems and other hardware automation scenarios where cloud-native distributed patterns meet embedded systems.
This skill helps you work with OrleansEdge-style architectures that combine:
Perfect for building reliable IoT edge systems that survive restarts, handle distributed state, and abstract hardware complexity.
The OrleansEdge system demonstrates a three-layer architecture:
1. **Shared Contracts Layer** (OrleansEdge.Core)
- Define grain interfaces (`ILedControllerGrain`)
- Share data models (enums, state types)
- Used by both client and node projects
2. **Edge Node Layer** (OrleansEdge.Node)
- Runs as Orleans silo on Raspberry Pi
- Implements grain logic with persistent state
- Communicates with hardware via Meadow OutputService
- Manages clustering and gateway endpoints
3. **Controller Layer** (OrleansEdge.Controller)
- Terminal UI client application
- Connects to Orleans cluster via static gateways
- Sends grain commands with full location transparency
Create grain interfaces and shared types in the Core project:
```csharp
// ILedControllerGrain.cs
public interface ILedControllerGrain : IGrainWithStringKey
{
Task SetLedColor(LedColor color);
Task<LedColor> GetCurrentColor();
}
// LedColor.cs
public enum LedColor
{
Off, Red, Green, Blue, Yellow, Cyan, Magenta, White
}
```
Create the grain implementation with SQLite-backed state:
```csharp
public class LedControllerGrain : Grain, ILedControllerGrain
{
private readonly IPersistentState<LedState> _state;
private readonly IOutputService _outputService;
public async Task SetLedColor(LedColor color)
{
_state.State.CurrentColor = color;
_state.State.LastUpdated = DateTime.UtcNow;
await _state.WriteStateAsync();
// Control hardware
await _outputService.SetLedAsync(color);
}
}
```
Set up the Orleans silo with clustering and persistence:
```csharp
// Program.cs
var builder = Host.CreateApplicationBuilder(args);
builder.UseOrleans((context, siloBuilder) =>
{
var config = context.Configuration;
siloBuilder
.UseDevelopmentClustering(options =>
{
options.PrimarySiloEndpoint =
new IPEndPoint(IPAddress.Parse("192.168.4.22"), 11111);
})
.ConfigureEndpoints(
siloPort: config.GetValue<int>("Orleans:SiloPort"),
gatewayPort: config.GetValue<int>("Orleans:GatewayPort")
)
.AddAdoNetGrainStorage("ledStorage", options =>
{
options.Invariant = "Microsoft.Data.Sqlite";
options.ConnectionString =
config.GetConnectionString("Orleans:Storage:ConnectionString");
});
});
```
Create the required Orleans storage schema:
```csharp
private static void InitializeSqliteDatabase(string connectionString)
{
using var connection = new SqliteConnection(connectionString);
connection.Open();
var createTableSql = @"
CREATE TABLE IF NOT EXISTS OrleansStorage (
GrainIdHash INTEGER NOT NULL,
ServiceId TEXT NOT NULL,
GrainIdN0 INTEGER NOT NULL,
GrainIdN1 INTEGER NOT NULL,
GrainTypeHash INTEGER NOT NULL,
GrainTypeString TEXT NOT NULL,
GrainIdExtensionString TEXT,
ServiceIdHash INTEGER NOT NULL,
PayloadBinary BLOB,
PayloadJson TEXT,
PayloadXml TEXT,
ModifiedOn TEXT NOT NULL,
Version INTEGER,
PRIMARY KEY(GrainIdHash, ServiceId)
);";
using var command = new SqliteCommand(createTableSql, connection);
command.ExecuteNonQuery();
}
```
Create a terminal-based UI to send commands:
```csharp
var builder = Host.CreateApplicationBuilder(args);
builder.UseOrleansClient((context, clientBuilder) =>
{
var gateways = context.Configuration
.GetSection("Orleans:Gateways")
.Get<string[]>();
clientBuilder.UseStaticClustering(
gateways.Select(g =>
{
var parts = g.Split(':');
return new IPEndPoint(
IPAddress.Parse(parts[0]),
int.Parse(parts[1])
);
}).ToArray()
);
});
// In your application logic
var grain = client.GetGrain<ILedControllerGrain>("led");
await grain.SetLedColor(LedColor.Red);
```
Use appsettings.{Environment}.json for different deployments:
**appsettings.Development.json**
```json
{
"Orleans": {
"SiloPort": 11111,
"GatewayPort": 30000,
"PrimarySiloEndpoint": "127.0.0.1:11111",
"Storage": {
"ConnectionString": "Data Source=orleans.db"
}
}
}
```
**appsettings.Production.json**
```json
{
"Orleans": {
"Gateways": ["192.168.5.3:30000"]
}
}
```
The Meadow platform provides hardware abstraction for Raspberry Pi LED control:
```csharp
public class OutputService : IOutputService
{
private readonly IDigitalOutputPort _led;
public async Task SetLedAsync(LedColor color)
{
_led.State = color != LedColor.Off;
}
}
```
Reference the Meadow projects from the wilderness directory:
Build the entire solution:
```bash
dotnet build OrleansEdge.slnx
```
Run locally for testing:
```bash
dotnet run --project OrleansEdge.Node/OrleansEdge.Node.csproj
dotnet run --project OrleansEdge.Controller/OrleansEdge.Controller.csproj
```
Deploy to Raspberry Pi:
1. Publish the Node project with Release configuration
2. Copy binaries to Raspberry Pi
3. Ensure appsettings.Production.json has correct IP addresses
4. Run with production environment variable
**Virtual Actor Pattern**: Each piece of hardware (LED) is represented by a grain with a unique identity. Orleans handles routing, activation, and location transparency automatically.
**State Persistence**: Grain state survives application restarts and grain deactivation. SQLite provides lightweight persistence suitable for edge devices.
**Hardware Abstraction**: Meadow platform isolates hardware-specific code, making it easier to port to different IoT platforms.
**Development Clustering**: `UseDevelopmentClustering()` simplifies local testing; switch to ADO.NET clustering for production multi-node setups.
This architecture can be adapted for:
The key is leveraging Orleans' location transparency and state management to simplify distributed edge computing challenges.
Leave a review
No reviews yet. Be the first to review this skill!
# Download SKILL.md from killerskills.ai/api/skills/orleans-edge-iot-control-2dphzp/raw