Components
Digital twin components in AgeDigitalTwins allow you to model complex entities by breaking them down into logical parts. Components provide a way to organize and manage different aspects of a digital twin, each with their own properties and telemetry.
Overview
Components in AgeDigitalTwins follow the DTDL (Digital Twins Definition Language) specification and provide:
- Modular Design: Break complex twins into manageable components
- Component-specific Operations: Read, update, and manage individual components
- Component Telemetry: Publish telemetry data specific to individual components
- DTDL Validation: Validate component data against DTDL models
- Azure Digital Twins Compatibility: Uses the same API patterns as Azure Digital Twins
How Components Work
Components are defined in your DTDL models and represent logical parts of a digital twin:
{
"@id": "dtmi:example:Building;1",
"@type": "Interface",
"displayName": "Building",
"contents": [
{
"@type": "Component",
"name": "hvac",
"schema": "dtmi:example:HVAC;1"
},
{
"@type": "Component",
"name": "lighting",
"schema": "dtmi:example:LightingSystem;1"
},
{
"@type": "Property",
"name": "buildingName",
"schema": "string"
}
]
}
Working with Components
Getting Component Data
Retrieve data for a specific component:
// Get HVAC component data from a building twin
var hvacData = await client.GetComponentAsync<HvacComponent>("building-001", "hvac");
Console.WriteLine($"Set Point: {hvacData.SetPoint}°C");
Console.WriteLine($"Current Temp: {hvacData.CurrentTemperature}°C");
Updating Components
Update specific properties within a component:
// Update HVAC component settings
var patch = new JsonPatchDocument();
patch.Replace("/SetPoint", 22.5);
patch.Replace("/Mode", "Auto");
await client.UpdateComponentAsync("building-001", "hvac", patch);
You can also update with a structured object:
// Update with an object
var hvacUpdate = new {
SetPoint = 23.0,
Mode = "Heat",
ScheduleEnabled = true
};
await client.UpdateComponentAsync("building-001", "hvac", hvacUpdate);
Component Validation
Components are automatically validated against their DTDL schema:
try
{
// This will validate against the HVAC component schema
await client.UpdateComponentAsync("building-001", "hvac", new {
SetPoint = "invalid-temperature", // This will fail validation
Mode = "InvalidMode" // This will also fail
});
}
catch (ValidationException ex)
{
Console.WriteLine($"Validation failed: {ex.Message}");
}
Component Telemetry
Components can publish their own telemetry data independently:
// Publish HVAC component telemetry
await client.PublishComponentTelemetryAsync("building-001", "hvac", new {
actualTemperature = 22.8,
energyUsage = 15.5,
fanSpeed = 75,
timestamp = DateTime.UtcNow
});
// Publish lighting component telemetry
await client.PublishComponentTelemetryAsync("building-001", "lighting", new {
brightnessLevel = 80,
energyUsage = 5.2,
motionDetected = true,
timestamp = DateTime.UtcNow
});
Component telemetry events include the component name in the subject:
{
"specversion": "1.0",
"type": "Konnektr.DigitalTwins.Component.Telemetry",
"source": "https://your-adt-instance/",
"subject": "building-001/components/hvac",
"data": {
"actualTemperature": 22.8,
"energyUsage": 15.5,
"fanSpeed": 75,
"timestamp": "2023-01-01T12:00:00Z"
}
}
Component Events
When you update components, lifecycle events are generated that include component context:
Component Update Event
{
"specversion": "1.0",
"type": "Konnektr.DigitalTwins.Twin.Update",
"source": "https://your-adt-instance/",
"subject": "building-001",
"data": {
"modelId": "dtmi:example:Building;1",
"patch": [
{
"op": "replace",
"path": "/hvac/SetPoint",
"value": 23.0
}
]
}
}
DTDL Component Definitions
Basic Component Schema
{
"@id": "dtmi:example:HVAC;1",
"@type": "Interface",
"displayName": "HVAC System",
"contents": [
{
"@type": "Property",
"name": "SetPoint",
"schema": "double",
"displayName": "Temperature Set Point",
"description": "Desired temperature in Celsius"
},
{
"@type": "Property",
"name": "Mode",
"schema": {
"@type": "Enum",
"valueSchema": "string",
"enumValues": [
{ "name": "Off", "enumValue": "Off" },
{ "name": "Heat", "enumValue": "Heat" },
{ "name": "Cool", "enumValue": "Cool" },
{ "name": "Auto", "enumValue": "Auto" }
]
}
},
{
"@type": "Telemetry",
"name": "ActualTemperature",
"schema": "double",
"displayName": "Actual Temperature"
}
]
}
Complex Component with Nested Properties
{
"@id": "dtmi:example:LightingSystem;1",
"@type": "Interface",
"displayName": "Lighting System",
"contents": [
{
"@type": "Property",
"name": "Zones",
"schema": {
"@type": "Map",
"mapKey": {
"name": "ZoneId",
"schema": "string"
},
"mapValue": {
"name": "ZoneSettings",
"schema": {
"@type": "Object",
"fields": [
{
"name": "brightness",
"schema": "integer"
},
{
"name": "colorTemperature",
"schema": "integer"
},
{
"name": "enabled",
"schema": "boolean"
}
]
}
}
}
}
]
}
Working with Nested Component Data
When components contain complex nested structures, you can work with them using dynamic objects or strongly-typed classes:
// Using dynamic object for flexibility
dynamic lighting = await client.GetComponentAsync("building-001", "lighting");
var zone1Brightness = lighting.Zones["zone1"].brightness;
// Using strongly-typed class for validation
public class LightingZoneSettings
{
public int Brightness { get; set; }
public int ColorTemperature { get; set; }
public bool Enabled { get; set; }
}
public class LightingComponent
{
public Dictionary<string, LightingZoneSettings> Zones { get; set; }
}
var lightingComponent = await client.GetComponentAsync<LightingComponent>("building-001", "lighting");
Component Best Practices
Design Guidelines
- Logical Separation: Group related properties and functionality into components
- Single Responsibility: Each component should have a clear, single purpose
- Naming Consistency: Use consistent naming conventions for component names and properties
- Documentation: Include clear descriptions in your DTDL schemas
Performance Considerations
- Granular Updates: Update specific components rather than entire twins when possible
- Component Telemetry: Use component-specific telemetry for better data organization
- Validation: Design component schemas for efficient validation
- Indexing: Consider indexing frequently accessed component properties
Error Handling
try
{
var component = await client.GetComponentAsync<HvacComponent>("building-001", "hvac");
}
catch (DigitalTwinNotFoundException)
{
// Twin doesn't exist
}
catch (ComponentNotFoundException)
{
// Component doesn't exist on the twin
}
catch (ValidationException ex)
{
// Component data doesn't match schema
Console.WriteLine($"Validation error: {ex.Message}");
}
Integration Patterns
IoT Device Integration
Map physical device capabilities to digital twin components:
// Map sensor data to appropriate components
public async Task UpdateFromIoTDevice(string twinId, IoTDeviceData data)
{
// Update HVAC component from temperature sensor
if (data.TemperatureSensor != null)
{
await client.UpdateComponentAsync(twinId, "hvac", new {
ActualTemperature = data.TemperatureSensor.Value,
LastUpdated = DateTime.UtcNow
});
}
// Update lighting component from occupancy sensor
if (data.OccupancySensor != null)
{
await client.UpdateComponentAsync(twinId, "lighting", new {
OccupancyDetected = data.OccupancySensor.Occupied,
LastMotion = data.OccupancySensor.LastMotionTime
});
}
}
System Integration
Use components to integrate with external building management systems:
// Sync with external BMS
public async Task SyncWithBuildingManagementSystem(string buildingId)
{
var bmsData = await _bmsClient.GetBuildingDataAsync(buildingId);
// Update each system component based on BMS data
await client.UpdateComponentAsync(buildingId, "hvac", new {
SetPoint = bmsData.HvacSetPoint,
Mode = bmsData.HvacMode,
ScheduleActive = bmsData.HvacScheduleEnabled
});
await client.UpdateComponentAsync(buildingId, "security", new {
AlarmArmed = bmsData.SecurityArmed,
AccessControlEnabled = bmsData.AccessControlActive
});
}
See Also
- DTDL Reference - Learn about Digital Twin Definition Language
- Validation - Understand how component validation works
- Telemetry - Learn about component-specific telemetry
- API Reference - Complete API documentation for component operations