Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Factory example #19

Open
wants to merge 35 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
06aad71
Start based on simple example
sgryphon Nov 17, 2021
d0c1c84
Add complex property with numbers, and a date proeprty
sgryphon Nov 17, 2021
7143ca8
Add full device model
sgryphon Nov 17, 2021
0ba608a
Inherit from base to get core props like etag
sgryphon Nov 17, 2021
112d12d
Add model creation option
sgryphon Nov 17, 2021
0d60cf9
Workarounds to get the parse happy with the output
sgryphon Nov 17, 2021
d64d8c1
WIP - deploy using Azure PowerShell
sgryphon Nov 26, 2021
4eb1b6f
WIP - script stuff
sgryphon Nov 30, 2021
d96cac9
Merge commit '05dd3932072a78ffc4b6caf2347e5bed48f435cf'
sgryphon Nov 30, 2021
ce8e878
Fix for deploy script
sgryphon Nov 30, 2021
0932938
Update org id in scripts
sgryphon Nov 30, 2021
7abdfb5
Initial exported arm & bicep files
sgryphon Nov 30, 2021
7279669
Working (but weird) ARM template
sgryphon Nov 30, 2021
20b81c9
Cleanup ARM example
sgryphon Nov 30, 2021
05cd72d
Update bicep example
sgryphon Dec 1, 2021
ae96c2b
Update powershell deployment
sgryphon Dec 1, 2021
b8199ff
Cleanup remove
sgryphon Dec 1, 2021
927959b
Merge commit '2b24cc5177a690c16fb89ad403a947a797ebb9fb'
sgryphon Dec 13, 2021
922c8c4
WIP - infrastructure scripts
sgryphon Dec 13, 2021
ef1fcb5
Update infrastructure scripts & check they run
sgryphon Dec 14, 2021
aadd9a0
Update sample objects for new library capabilities (semantic types, etc)
sgryphon Dec 14, 2021
58854af
Convert example back to .NET 3.1 LTS
sgryphon Dec 14, 2021
4302111
Reorg example into files
sgryphon Dec 14, 2021
ff487e0
Code cleanup
sgryphon Dec 14, 2021
d298cea
Mode code cleanup
sgryphon Dec 14, 2021
4d5fed9
Reorganise scripts, add data permissions
sgryphon Dec 15, 2021
7a16882
Add create function; update readme instructions - can successfully cr…
sgryphon Dec 15, 2021
5027fbe
Can successfully create a twin instance
sgryphon Dec 15, 2021
0763c13
Update readme with instructions to view results in explorer
sgryphon Dec 15, 2021
e77ade9
Code cleanup
sgryphon Dec 15, 2021
ad70021
Second twin instance, with relationship
sgryphon Dec 18, 2021
5d43e35
Code cleanup
sgryphon Dec 18, 2021
15cab53
Create all example entities
sgryphon Dec 18, 2021
bbdce19
Add explorer pictures to readme
sgryphon Dec 18, 2021
c39e733
Tweak to make example serializer show the concrete object properties
sgryphon Mar 30, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions DigitalTwins-CodeFirst-dotnet.sln
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{D8068994
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Telstra.Twins.Test", "Tests\Telstra.Twins.Test\Telstra.Twins.Test.csproj", "{4E5BF74D-C0EF-4D13-872C-F40FC347AD67}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{5BA14B5E-B883-4B92-802D-0BA49C93842B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FactoryExample", "Examples\FactoryExample\FactoryExample.csproj", "{B1000F84-515B-4406-8B11-CC80051C531A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{2249F79B-DD17-4FAF-91B7-3E69A5E9546C}"
ProjectSection(SolutionItems) = preProject
README.md = README.md
Expand Down Expand Up @@ -67,8 +71,21 @@ Global
{4E5BF74D-C0EF-4D13-872C-F40FC347AD67}.Release|x64.Build.0 = Release|Any CPU
{4E5BF74D-C0EF-4D13-872C-F40FC347AD67}.Release|x86.ActiveCfg = Release|Any CPU
{4E5BF74D-C0EF-4D13-872C-F40FC347AD67}.Release|x86.Build.0 = Release|Any CPU
{B1000F84-515B-4406-8B11-CC80051C531A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B1000F84-515B-4406-8B11-CC80051C531A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B1000F84-515B-4406-8B11-CC80051C531A}.Debug|x64.ActiveCfg = Debug|Any CPU
{B1000F84-515B-4406-8B11-CC80051C531A}.Debug|x64.Build.0 = Debug|Any CPU
{B1000F84-515B-4406-8B11-CC80051C531A}.Debug|x86.ActiveCfg = Debug|Any CPU
{B1000F84-515B-4406-8B11-CC80051C531A}.Debug|x86.Build.0 = Debug|Any CPU
{B1000F84-515B-4406-8B11-CC80051C531A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B1000F84-515B-4406-8B11-CC80051C531A}.Release|Any CPU.Build.0 = Release|Any CPU
{B1000F84-515B-4406-8B11-CC80051C531A}.Release|x64.ActiveCfg = Release|Any CPU
{B1000F84-515B-4406-8B11-CC80051C531A}.Release|x64.Build.0 = Release|Any CPU
{B1000F84-515B-4406-8B11-CC80051C531A}.Release|x86.ActiveCfg = Release|Any CPU
{B1000F84-515B-4406-8B11-CC80051C531A}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{4E5BF74D-C0EF-4D13-872C-F40FC347AD67} = {D8068994-FDA6-41F1-9196-59AADA892F11}
{B1000F84-515B-4406-8B11-CC80051C531A} = {5BA14B5E-B883-4B92-802D-0BA49C93842B}
EndGlobalSection
EndGlobal
1 change: 1 addition & 0 deletions DigitalTwins-CodeFirst-dotnet.sln.DotSettings
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/UserDictionary/Words/=appsettings/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Dtdl/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
158 changes: 158 additions & 0 deletions Examples/FactoryExample/CreateExample.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
using System;
using System.Linq;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Azure.DigitalTwins.Core;
using Azure.Identity;
using Telstra.Twins.Core;
using Telstra.Twins.Services;

namespace FactoryExample
{
public static class CreateExample
{
//public static async Task CreateModels(string tenantId, string clientId, string clientSecret, string adtEndpoint)
public static async Task CreateModelsAsync(string adtEndpoint, CancellationToken cancellationToken)
{
var modelLibrary = new ModelLibrary();
var serializer = new DigitalTwinSerializer(modelLibrary);

var models = Program.ModelTypes.Select(x => serializer.SerializeModel(x));

try
{
//var client = GetDigitalTwinsClient(tenantId, clientId, clientSecret, adtEndpoint);
var client = GetDigitalTwinsClient(adtEndpoint);
var response = await client.CreateModelsAsync(models, cancellationToken);
Console.WriteLine("CREATE MODELS SUCCESS");
foreach (var modelData in response.Value)
{
Console.WriteLine(
$"{modelData.Id}: {modelData.LanguageDisplayNames.FirstOrDefault().Value}");
}
}
catch (Exception ex)
{
Console.WriteLine($"CREATE FAILED: {ex.Message}");
}
}

public static async Task CreateTwinsAsync(string adtEndpoint, CancellationToken cancellationToken)
{
var modelLibrary = new ModelLibrary();
var serializer = new DigitalTwinSerializer(modelLibrary);

var factory = Program.CreateFactoryTwin();

try
{
//var client = GetDigitalTwinsClient(tenantId, clientId, clientSecret, adtEndpoint);
var client = GetDigitalTwinsClient(adtEndpoint);

await CreateTwinInstanceAsync(client, factory.FactoryId, serializer.SerializeTwin(factory),
cancellationToken);

foreach (var floor in factory.Floors)
{
await CreateTwinInstanceAsync(client, floor.FloorId, serializer.SerializeTwin(floor),
cancellationToken);
await CreateTwinRelationshipAsync(client, "floors", factory.FactoryId,
floor.FloorId, cancellationToken);

foreach (var line in floor.RunsLines)
{
await CreateTwinInstanceAsync(client, line.LineId, serializer.SerializeTwin(line),
cancellationToken);
await CreateTwinRelationshipAsync(client, "runsLines", floor.FloorId,
line.LineId, cancellationToken);

foreach (var step in line.RunsSteps)
{
await CreateTwinInstanceAsync(client, step.StepId, serializer.SerializeTwin(step),
cancellationToken);
await CreateTwinRelationshipAsync(client, "runsSteps", line.LineId,
step.StepId, cancellationToken);
}

foreach (var step in line.RunsSteps)
{
if (step.StepLink != null)
{
await CreateTwinRelationshipAsync(client, "stepLink", step.StepId,
step.StepLink.StepId, cancellationToken);
}
}
}
}
}
catch (Exception ex)
{
Console.WriteLine($"CREATE FAILED: {ex.Message}");
}
}

private static async Task CreateTwinInstanceAsync(DigitalTwinsClient client, string? id, string dtdl,
CancellationToken cancellationToken)
{
if (id == null)
{
throw new ArgumentNullException(nameof(id));
}

var basicDigitalTwin = JsonSerializer.Deserialize<BasicDigitalTwin>(dtdl);
var response =
await client.CreateOrReplaceDigitalTwinAsync(id, basicDigitalTwin, null, cancellationToken);
if (response?.Value != null)
{
Console.WriteLine("CREATE TWIN SUCCESS: Id={0}, ETag={1}", response.Value.Id,
response.Value.ETag);
}
}

private static async Task CreateTwinRelationshipAsync(DigitalTwinsClient client,
string relationshipName, string? sourceId, string? targetId, CancellationToken cancellationToken)
{
if (sourceId == null)
{
throw new ArgumentNullException(nameof(sourceId));
}

if (targetId == null)
{
throw new ArgumentNullException(nameof(targetId));
}

var relationship = new BasicRelationship
{
Id = $"{sourceId}_{targetId}",
Name = relationshipName,
SourceId = sourceId,
TargetId = targetId
};
var response = await client.CreateOrReplaceRelationshipAsync(sourceId, relationship.Id,
relationship, null, cancellationToken);
Console.WriteLine("CREATE RELATIONSHIP SUCCESS: Id={0}, ETag={1}", response.Value.Id,
response.Value.ETag);
}

private static DigitalTwinsClient GetDigitalTwinsClient(string adtEndpoint)
//private static DigitalTwinsClient GetDigitalTwinsClient(string tenantId, string clientId, string clientSecret, string adtEndpoint)
{
// These environment variables are necessary for DefaultAzureCredential to use application Id and client secret to login.
//Environment.SetEnvironmentVariable("AZURE_CLIENT_SECRET", clientSecret);
//Environment.SetEnvironmentVariable("AZURE_CLIENT_ID", clientId);
//Environment.SetEnvironmentVariable("AZURE_TENANT_ID", tenantId);

// DefaultAzureCredential supports different authentication mechanisms and determines the appropriate credential type based of the environment it is executing in.
// It attempts to use multiple credential types in an order until it finds a working credential.
var tokenCredential = new DefaultAzureCredential(true);

var client = new DigitalTwinsClient(
new Uri(adtEndpoint),
tokenCredential);

return client;
}
}
}
27 changes: 27 additions & 0 deletions Examples/FactoryExample/Devices/ProductionStep.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System;
using Telstra.Twins;
using Telstra.Twins.Attributes;

namespace FactoryExample.Devices
{
[DigitalTwin(Version = 1, DisplayName = "Factory Production Steps - Interface Model")]
public class ProductionStep : TwinBase
{
// ContainsEquipment

[TwinProperty] public bool FinalStep { get; set; }

// HasConnectedDevices

//[TwinProperty] public ProductionStepStatus OperationStatus { get; set; }

[TwinProperty] public DateTimeOffset? StartTime { get; set; }

[TwinProperty] public string? StepId { get; set; }

[TwinRelationship(DisplayName = "Step Link")]
public ProductionStep? StepLink { get; set; }

[TwinProperty] public string? StepName { get; set; }
}
}
23 changes: 23 additions & 0 deletions Examples/FactoryExample/Devices/ProductionStepFanning.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using Telstra.Twins.Attributes;
using Telstra.Twins.Semantics;

namespace FactoryExample.Devices
{
[DigitalTwin(Version = 1, DisplayName = "Factory Production Step: Fanning/Roasting - Interface Model",
ExtendsModelId = "dtmi:factoryexample:devices:productionstep;1")]
public class ProductionStepFanning : ProductionStep
{
[TwinProperty(SemanticType = SemanticType.Temperature, Unit = TemperatureUnit.DegreeCelsius,
Writable = true)]
public double? ChassisTemperature { get; set; }

[TwinProperty]
public double? FanSpeed { get; set; }

[TwinProperty(SemanticType = SemanticType.TimeSpan, Unit = TimeUnit.Minute)]
public int? RoastingTime { get; set; }

[TwinProperty(SemanticType = SemanticType.Power, Unit = PowerUnit.Kilowatt)]
public double? PowerUsage { get; set; }
}
}
26 changes: 26 additions & 0 deletions Examples/FactoryExample/Devices/ProductionStepGrinding.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using Telstra.Twins.Attributes;
using Telstra.Twins.Semantics;

namespace FactoryExample.Devices
{
[DigitalTwin(Version = 1, DisplayName = "Factory Production Step: Grinding/Crushing - Interface Model",
ExtendsModelId = "dtmi:factoryexample:devices:productionstep;1")]
public class ProductionStepGrinding : ProductionStep
{
[TwinProperty(SemanticType = SemanticType.Temperature, Unit = TemperatureUnit.DegreeCelsius,
Writable = true)]
public double? ChassisTemperature { get; set; }

[TwinProperty(SemanticType = SemanticType.Force, Unit = ForceUnit.Newton)]
public double? Force { get; set; }

[TwinProperty(SemanticType = SemanticType.TimeSpan, Unit = TimeUnit.Minute)]
public int? GrindingTime { get; set; }

[TwinProperty(SemanticType = SemanticType.Power, Unit = PowerUnit.Kilowatt)]
public double? PowerUsage { get; set; }

[TwinProperty(SemanticType = SemanticType.Frequency, Unit = FrequencyUnit.Hertz)]
public double? Vibration { get; set; }
}
}
17 changes: 17 additions & 0 deletions Examples/FactoryExample/Devices/ProductionStepMoulding.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using Telstra.Twins.Attributes;
using Telstra.Twins.Semantics;

namespace FactoryExample.Devices
{
[DigitalTwin(Version = 1, DisplayName = "Factory Production Step: Moulding - Interface Model",
ExtendsModelId = "dtmi:factoryexample:devices:productionstep;1")]
public class ProductionStepMoulding : ProductionStep
{
[TwinProperty(SemanticType = SemanticType.Temperature, Unit = TemperatureUnit.DegreeCelsius,
Writable = true)]
public double? ChassisTemperature { get; set; }

[TwinProperty]
public double? PowerUsage { get; set; }
}
}
9 changes: 9 additions & 0 deletions Examples/FactoryExample/Devices/ProductionStepStatus.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace FactoryExample.Devices
{
public enum ProductionStepStatus
{
Unknown = 0,
Offline = 1,
Online = 2
}
}
17 changes: 17 additions & 0 deletions Examples/FactoryExample/FactoryExample.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\Telstra.Twins\Telstra.Twins.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Azure.Identity" Version="1.5.0" />
</ItemGroup>

</Project>
33 changes: 33 additions & 0 deletions Examples/FactoryExample/Models/Factory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using FactoryExample.Schema;
using Telstra.Twins;
using Telstra.Twins.Attributes;

namespace FactoryExample.Models
{
[DigitalTwin(Version = 1, DisplayName = "Digital Factory - Interface Model")]
public class Factory : TwinBase
{
[TwinProperty] public string? Country { get; set; }

[TwinProperty] public string? FactoryId { get; set; }

[TwinProperty(Writable = true)] public string? FactoryName { get; set; }

[TwinRelationship(DisplayName = "Has Floors")]
public IList<FactoryFloor> Floors { get; } = new List<FactoryFloor>();

[TwinProperty] public GeoCord? GeoLocation { get; set; }

[TwinProperty] public DateTimeOffset LastSupplyDate { get; set; }

// ServesRetailer
// SuppliedBy
// TransportationBy

[TwinProperty(Writable = true)] public string? Tags { get; set; }

[TwinProperty(Writable = true)] public string? ZipCode { get; set; }
}
}
27 changes: 27 additions & 0 deletions Examples/FactoryExample/Models/FactoryFloor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System.Collections.Generic;
using Telstra.Twins;
using Telstra.Twins.Attributes;
using Telstra.Twins.Semantics;

namespace FactoryExample.Models
{
[DigitalTwin(Version = 1, DisplayName = "Digital Factory - Interface Model")]
public class FactoryFloor : TwinBase
{
[TwinProperty] public double? ComfortIndex { get; set; }

[TwinProperty(Writable = true)] public string? FloorId { get; set; }

// FloorHasRooms
// FloorHasZones

[TwinProperty(Writable = true)] public string? FloorName { get; set; }

[TwinRelationship(DisplayName = "Runs Production Lines")]
public IList<ProductionLine> RunsLines { get; } = new List<ProductionLine>();

[TwinProperty(SemanticType = SemanticType.Temperature, Unit = TemperatureUnit.DegreeCelsius,
Writable = true)]
public double? Temperature { get; set; }
}
}
Loading