From 06aad7109119e72082b4b0a16a77b90901d94082 Mon Sep 17 00:00:00 2001 From: Sly Gryphon Date: Wed, 17 Nov 2021 19:10:36 +1000 Subject: [PATCH 01/33] Start based on simple example --- DigitalTwins-CodeFirst-dotnet.sln | 17 +++++++++ Examples/FactoryExample/FactoryExample.csproj | 14 +++++++ Examples/FactoryExample/Models/Factory.cs | 20 ++++++++++ .../FactoryExample/Models/FactoryFloor.cs | 12 ++++++ Examples/FactoryExample/Program.cs | 37 +++++++++++++++++++ 5 files changed, 100 insertions(+) create mode 100644 Examples/FactoryExample/FactoryExample.csproj create mode 100644 Examples/FactoryExample/Models/Factory.cs create mode 100644 Examples/FactoryExample/Models/FactoryFloor.cs create mode 100644 Examples/FactoryExample/Program.cs diff --git a/DigitalTwins-CodeFirst-dotnet.sln b/DigitalTwins-CodeFirst-dotnet.sln index 6f4f13c..51933ea 100644 --- a/DigitalTwins-CodeFirst-dotnet.sln +++ b/DigitalTwins-CodeFirst-dotnet.sln @@ -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 Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -60,8 +64,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 diff --git a/Examples/FactoryExample/FactoryExample.csproj b/Examples/FactoryExample/FactoryExample.csproj new file mode 100644 index 0000000..80d533b --- /dev/null +++ b/Examples/FactoryExample/FactoryExample.csproj @@ -0,0 +1,14 @@ + + + + Exe + net6.0 + enable + enable + + + + + + + diff --git a/Examples/FactoryExample/Models/Factory.cs b/Examples/FactoryExample/Models/Factory.cs new file mode 100644 index 0000000..878309d --- /dev/null +++ b/Examples/FactoryExample/Models/Factory.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using Telstra.Twins.Attributes; + +namespace FactoryExample.Models +{ + [DigitalTwin(Version = 1, DisplayName = "Digital Factory - Interface Model")] + public class Factory + { + [TwinProperty] public string? Country { get; set; } + + [TwinProperty] public string? FactoryId { get; set; } + + [TwinProperty] public string? FactoryName { get; set; } + + [TwinRelationship(DisplayName = "Has Floors")] + public List Floors { get; set; } = new(); + + [TwinProperty] public string? ZipCode { get; set; } + } +} diff --git a/Examples/FactoryExample/Models/FactoryFloor.cs b/Examples/FactoryExample/Models/FactoryFloor.cs new file mode 100644 index 0000000..aec8292 --- /dev/null +++ b/Examples/FactoryExample/Models/FactoryFloor.cs @@ -0,0 +1,12 @@ +using Telstra.Twins.Attributes; + +namespace FactoryExample.Models +{ + [DigitalTwin(Version = 1, DisplayName = "Digital Factory - Interface Model")] + public class FactoryFloor + { + [TwinProperty] public string? FloorId { get; set; } + + [TwinProperty] public string? FloorName { get; set; } + } +} diff --git a/Examples/FactoryExample/Program.cs b/Examples/FactoryExample/Program.cs new file mode 100644 index 0000000..1a947b0 --- /dev/null +++ b/Examples/FactoryExample/Program.cs @@ -0,0 +1,37 @@ +using System; +using FactoryExample.Models; +using Telstra.Twins.Core; +using Telstra.Twins.Services; + +Console.WriteLine("Digital Twin Code First Factory Example"); + +var modelLibrary = new ModelLibrary(); +var serializer = new DigitalTwinSerializer(modelLibrary); + +Console.WriteLine("Models:"); +Console.WriteLine(); + +var model1Dtdl = serializer.SerializeModel(); +Console.WriteLine(model1Dtdl); +Console.WriteLine(); + +var model2Dtdl = serializer.SerializeModel(); +Console.WriteLine(model2Dtdl); +Console.WriteLine(); + +Console.WriteLine("Twins:"); +Console.WriteLine(); + +var factory = new Factory +{ + FactoryId = "factory1", Country = "AU", ZipCode = "4000", FactoryName = "Chocolate Factory" +}; +factory.Floors.Add(new FactoryFloor { FloorId = "floor1", FloorName = "Floor 1" }); + +var twin1Dtdl = serializer.SerializeTwin(factory); +Console.WriteLine(twin1Dtdl); +Console.WriteLine(); + +var twin2Dtdl = serializer.SerializeTwin(factory.Floors[0]); +Console.WriteLine(twin2Dtdl); +Console.WriteLine(); From d0c1c84c8f2cc0a3753b314908c911fd09f13c2a Mon Sep 17 00:00:00 2001 From: Sly Gryphon Date: Wed, 17 Nov 2021 19:14:34 +1000 Subject: [PATCH 02/33] Add complex property with numbers, and a date proeprty --- Examples/FactoryExample/Models/Factory.cs | 8 +++++++- Examples/FactoryExample/Program.cs | 10 ++++++++-- Examples/FactoryExample/Schema/GeoCord.cs | 11 +++++++++++ 3 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 Examples/FactoryExample/Schema/GeoCord.cs diff --git a/Examples/FactoryExample/Models/Factory.cs b/Examples/FactoryExample/Models/Factory.cs index 878309d..ae24426 100644 --- a/Examples/FactoryExample/Models/Factory.cs +++ b/Examples/FactoryExample/Models/Factory.cs @@ -1,4 +1,6 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using FactoryExample.Schema; using Telstra.Twins.Attributes; namespace FactoryExample.Models @@ -15,6 +17,10 @@ public class Factory [TwinRelationship(DisplayName = "Has Floors")] public List Floors { get; set; } = new(); + [TwinProperty] public GeoCord? GeoLocation { get; set; } + + [TwinProperty] public DateTimeOffset LastSupplyDate { get; set; } + [TwinProperty] public string? ZipCode { get; set; } } } diff --git a/Examples/FactoryExample/Program.cs b/Examples/FactoryExample/Program.cs index 1a947b0..290d6ef 100644 --- a/Examples/FactoryExample/Program.cs +++ b/Examples/FactoryExample/Program.cs @@ -1,9 +1,10 @@ using System; using FactoryExample.Models; +using FactoryExample.Schema; using Telstra.Twins.Core; using Telstra.Twins.Services; -Console.WriteLine("Digital Twin Code First Factory Example"); +Console.WriteLine("Simple Digital Twin Serializer Example"); var modelLibrary = new ModelLibrary(); var serializer = new DigitalTwinSerializer(modelLibrary); @@ -24,7 +25,12 @@ var factory = new Factory { - FactoryId = "factory1", Country = "AU", ZipCode = "4000", FactoryName = "Chocolate Factory" + FactoryId = "factory1", + Country = "AU", + ZipCode = "4000", + FactoryName = "Chocolate Factory", + GeoLocation = new GeoCord() { Latitude = -27.4705, Longitude = 153.026 }, + LastSupplyDate = new DateTimeOffset(2021, 11, 17, 18, 37, 0, TimeSpan.FromHours(10)) }; factory.Floors.Add(new FactoryFloor { FloorId = "floor1", FloorName = "Floor 1" }); diff --git a/Examples/FactoryExample/Schema/GeoCord.cs b/Examples/FactoryExample/Schema/GeoCord.cs new file mode 100644 index 0000000..8fb250a --- /dev/null +++ b/Examples/FactoryExample/Schema/GeoCord.cs @@ -0,0 +1,11 @@ +using Telstra.Twins.Attributes; + +namespace FactoryExample.Schema +{ + [DigitalTwin(Version = 1)] + public class GeoCord + { + [TwinProperty("lat")] public double Latitude { get; set; } + [TwinProperty("lon")] public double Longitude { get; set; } + } +} From 7143ca8242001be365741d62b86f0929d090af96 Mon Sep 17 00:00:00 2001 From: Sly Gryphon Date: Wed, 17 Nov 2021 19:58:31 +1000 Subject: [PATCH 03/33] Add full device model --- .../FactoryExample/Devices/ProductionStep.cs | 22 ++++++++ .../Devices/ProductionStepGrinding.cs | 24 +++++++++ .../Devices/ProductionStepStatus.cs | 9 ++++ Examples/FactoryExample/Models/Factory.cs | 2 +- .../FactoryExample/Models/FactoryFloor.cs | 11 +++- .../FactoryExample/Models/ProductionLine.cs | 23 ++++++++ .../Models/ProductionLineStatus.cs | 9 ++++ Examples/FactoryExample/Program.cs | 54 +++++++++++++++---- 8 files changed, 142 insertions(+), 12 deletions(-) create mode 100644 Examples/FactoryExample/Devices/ProductionStep.cs create mode 100644 Examples/FactoryExample/Devices/ProductionStepGrinding.cs create mode 100644 Examples/FactoryExample/Devices/ProductionStepStatus.cs create mode 100644 Examples/FactoryExample/Models/ProductionLine.cs create mode 100644 Examples/FactoryExample/Models/ProductionLineStatus.cs diff --git a/Examples/FactoryExample/Devices/ProductionStep.cs b/Examples/FactoryExample/Devices/ProductionStep.cs new file mode 100644 index 0000000..63184b4 --- /dev/null +++ b/Examples/FactoryExample/Devices/ProductionStep.cs @@ -0,0 +1,22 @@ +using System; +using Telstra.Twins.Attributes; + +namespace FactoryExample.Devices +{ + [DigitalTwin(Version = 1, DisplayName = "Factory Production Steps - Interface Model")] + public class ProductionStep + { + [TwinProperty] public bool FinalStep { get; set; } + + [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; } + } +} diff --git a/Examples/FactoryExample/Devices/ProductionStepGrinding.cs b/Examples/FactoryExample/Devices/ProductionStepGrinding.cs new file mode 100644 index 0000000..480a0ee --- /dev/null +++ b/Examples/FactoryExample/Devices/ProductionStepGrinding.cs @@ -0,0 +1,24 @@ +using Telstra.Twins.Attributes; + +namespace FactoryExample.Devices +{ + [DigitalTwin(Version = 1, DisplayName = "Factory Production Step: Grinding/Crushing - Interface Model", + ExtendsModelId = "dtmi:factoryexample:devices:productionstep;1")] + public class ProductionStepGrinding : ProductionStep + { + [TwinTelemetry(Unit = "degreeCelsius", SemanticType = "Temperature")] + public double? ChassisTemperature { get; set; } + + [TwinTelemetry(Unit = "newton", SemanticType = "Force")] + public double? Force { get; set; } + + [TwinTelemetry(Unit = "minute", SemanticType = "TimeSpan")] + public int? GrindingTime { get; set; } + + [TwinTelemetry(Unit = "kilowatt", SemanticType = "Power")] + public double? PowerUsage { get; set; } + + [TwinTelemetry(Unit = "hertz", SemanticType = "Frequency")] + public double? Vibration { get; set; } + } +} diff --git a/Examples/FactoryExample/Devices/ProductionStepStatus.cs b/Examples/FactoryExample/Devices/ProductionStepStatus.cs new file mode 100644 index 0000000..ca629e8 --- /dev/null +++ b/Examples/FactoryExample/Devices/ProductionStepStatus.cs @@ -0,0 +1,9 @@ +namespace FactoryExample.Devices +{ + public enum ProductionStepStatus + { + Unknown = 0, + Offline = 1, + Online = 2 + } +} diff --git a/Examples/FactoryExample/Models/Factory.cs b/Examples/FactoryExample/Models/Factory.cs index ae24426..c4de5ad 100644 --- a/Examples/FactoryExample/Models/Factory.cs +++ b/Examples/FactoryExample/Models/Factory.cs @@ -15,7 +15,7 @@ public class Factory [TwinProperty] public string? FactoryName { get; set; } [TwinRelationship(DisplayName = "Has Floors")] - public List Floors { get; set; } = new(); + public IList Floors { get; } = new List(); [TwinProperty] public GeoCord? GeoLocation { get; set; } diff --git a/Examples/FactoryExample/Models/FactoryFloor.cs b/Examples/FactoryExample/Models/FactoryFloor.cs index aec8292..fcc9278 100644 --- a/Examples/FactoryExample/Models/FactoryFloor.cs +++ b/Examples/FactoryExample/Models/FactoryFloor.cs @@ -1,12 +1,21 @@ -using Telstra.Twins.Attributes; +using System.Collections.Generic; +using Telstra.Twins.Attributes; namespace FactoryExample.Models { [DigitalTwin(Version = 1, DisplayName = "Digital Factory - Interface Model")] public class FactoryFloor { + [TwinProperty] public double? ComfortIndex { get; set; } + [TwinProperty] public string? FloorId { get; set; } [TwinProperty] public string? FloorName { get; set; } + + [TwinRelationship(DisplayName = "Runs Production Lines")] + public IList RunsLines { get; } = new List(); + + [TwinTelemetry(Unit = "degreeCelsius", SemanticType = "Temperature")] + public double? Temperature { get; set; } } } diff --git a/Examples/FactoryExample/Models/ProductionLine.cs b/Examples/FactoryExample/Models/ProductionLine.cs new file mode 100644 index 0000000..791ff81 --- /dev/null +++ b/Examples/FactoryExample/Models/ProductionLine.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using FactoryExample.Devices; +using Telstra.Twins.Attributes; + +namespace FactoryExample.Models +{ + [DigitalTwin(Version = 1, DisplayName = "Factory Production Line - Interface Model")] + public class ProductionLine + { + [TwinProperty] public string? CurrentProductId { get; set; } + + [TwinProperty] public string? LineId { get; set; } + + [TwinProperty] public string? LineName { get; set; } + + [TwinProperty] public ProductionLineStatus LineOperationStatus { get; set; } + + [TwinProperty] public int? ProductBatchNumber { get; set; } + + [TwinRelationship(DisplayName = "Runs Steps")] + public IList RunsSteps { get; } = new List(); + } +} diff --git a/Examples/FactoryExample/Models/ProductionLineStatus.cs b/Examples/FactoryExample/Models/ProductionLineStatus.cs new file mode 100644 index 0000000..b1bc2ce --- /dev/null +++ b/Examples/FactoryExample/Models/ProductionLineStatus.cs @@ -0,0 +1,9 @@ +namespace FactoryExample.Models +{ + public enum ProductionLineStatus + { + Unknown = 0, + Offline = 1, + Online = 2 + } +} diff --git a/Examples/FactoryExample/Program.cs b/Examples/FactoryExample/Program.cs index 290d6ef..25758fe 100644 --- a/Examples/FactoryExample/Program.cs +++ b/Examples/FactoryExample/Program.cs @@ -1,4 +1,5 @@ using System; +using FactoryExample.Devices; using FactoryExample.Models; using FactoryExample.Schema; using Telstra.Twins.Core; @@ -12,32 +13,65 @@ Console.WriteLine("Models:"); Console.WriteLine(); -var model1Dtdl = serializer.SerializeModel(); -Console.WriteLine(model1Dtdl); -Console.WriteLine(); - -var model2Dtdl = serializer.SerializeModel(); -Console.WriteLine(model2Dtdl); -Console.WriteLine(); +var modelTypes = new[] +{ + typeof(Factory), typeof(FactoryFloor), typeof(ProductionLine), typeof(ProductionStep), + typeof(ProductionStepGrinding) +}; +foreach (var modelType in modelTypes) +{ + var modelDtdl = serializer.SerializeModel(modelType); + Console.WriteLine(modelDtdl); + Console.WriteLine(); +} Console.WriteLine("Twins:"); Console.WriteLine(); +var productionStepGrinding = new ProductionStepGrinding +{ + ChassisTemperature = 50, + FinalStep = false, + Force = 8.0, + GrindingTime = 30, + OperationStatus = ProductionStepStatus.Online, + PowerUsage = 100, + StartTime = new DateTimeOffset(2021, 11, 17, 19, 57, 0, TimeSpan.FromHours(10)), + StepId = "step1", + StepName = "GrindingStep" +}; + +var productionLine = new ProductionLine +{ + CurrentProductId = "production1", + LineId = "line1", + LineName = "ProductionLine", + LineOperationStatus = ProductionLineStatus.Online, + ProductBatchNumber = 5 +}; +productionLine.RunsSteps.Add(productionStepGrinding); + +var factoryFloor = new FactoryFloor +{ + FloorId = "floor1", FloorName = "FactoryFloor", Temperature = 23, ComfortIndex = 0.8 +}; +factoryFloor.RunsLines.Add(productionLine); + var factory = new Factory { FactoryId = "factory1", Country = "AU", ZipCode = "4000", FactoryName = "Chocolate Factory", - GeoLocation = new GeoCord() { Latitude = -27.4705, Longitude = 153.026 }, + GeoLocation = new GeoCord { Latitude = -27.4705, Longitude = 153.026 }, LastSupplyDate = new DateTimeOffset(2021, 11, 17, 18, 37, 0, TimeSpan.FromHours(10)) }; -factory.Floors.Add(new FactoryFloor { FloorId = "floor1", FloorName = "Floor 1" }); +factory.Floors.Add(factoryFloor); var twin1Dtdl = serializer.SerializeTwin(factory); Console.WriteLine(twin1Dtdl); Console.WriteLine(); -var twin2Dtdl = serializer.SerializeTwin(factory.Floors[0]); +var twin2Dtdl = serializer.SerializeTwin(factory.Floors[0].RunsLines[0].RunsSteps[0]); Console.WriteLine(twin2Dtdl); Console.WriteLine(); From 0ba608aaf9af3533caf62fb7e3c97aa57470fa14 Mon Sep 17 00:00:00 2001 From: Sly Gryphon Date: Wed, 17 Nov 2021 20:21:20 +1000 Subject: [PATCH 04/33] Inherit from base to get core props like etag --- Examples/FactoryExample/Devices/ProductionStep.cs | 3 ++- Examples/FactoryExample/Models/Factory.cs | 3 ++- Examples/FactoryExample/Models/FactoryFloor.cs | 3 ++- Examples/FactoryExample/Models/ProductionLine.cs | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Examples/FactoryExample/Devices/ProductionStep.cs b/Examples/FactoryExample/Devices/ProductionStep.cs index 63184b4..0aecf5c 100644 --- a/Examples/FactoryExample/Devices/ProductionStep.cs +++ b/Examples/FactoryExample/Devices/ProductionStep.cs @@ -1,10 +1,11 @@ using System; +using Telstra.Twins; using Telstra.Twins.Attributes; namespace FactoryExample.Devices { [DigitalTwin(Version = 1, DisplayName = "Factory Production Steps - Interface Model")] - public class ProductionStep + public class ProductionStep : Device { [TwinProperty] public bool FinalStep { get; set; } diff --git a/Examples/FactoryExample/Models/Factory.cs b/Examples/FactoryExample/Models/Factory.cs index c4de5ad..a7fb5ba 100644 --- a/Examples/FactoryExample/Models/Factory.cs +++ b/Examples/FactoryExample/Models/Factory.cs @@ -1,12 +1,13 @@ 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 + public class Factory : TwinBase { [TwinProperty] public string? Country { get; set; } diff --git a/Examples/FactoryExample/Models/FactoryFloor.cs b/Examples/FactoryExample/Models/FactoryFloor.cs index fcc9278..6a72b92 100644 --- a/Examples/FactoryExample/Models/FactoryFloor.cs +++ b/Examples/FactoryExample/Models/FactoryFloor.cs @@ -1,10 +1,11 @@ using System.Collections.Generic; +using Telstra.Twins; using Telstra.Twins.Attributes; namespace FactoryExample.Models { [DigitalTwin(Version = 1, DisplayName = "Digital Factory - Interface Model")] - public class FactoryFloor + public class FactoryFloor : TwinBase { [TwinProperty] public double? ComfortIndex { get; set; } diff --git a/Examples/FactoryExample/Models/ProductionLine.cs b/Examples/FactoryExample/Models/ProductionLine.cs index 791ff81..e4a83a8 100644 --- a/Examples/FactoryExample/Models/ProductionLine.cs +++ b/Examples/FactoryExample/Models/ProductionLine.cs @@ -1,11 +1,12 @@ using System.Collections.Generic; using FactoryExample.Devices; +using Telstra.Twins; using Telstra.Twins.Attributes; namespace FactoryExample.Models { [DigitalTwin(Version = 1, DisplayName = "Factory Production Line - Interface Model")] - public class ProductionLine + public class ProductionLine : TwinBase { [TwinProperty] public string? CurrentProductId { get; set; } From 112d12df0bc2b2b750aaa0fa36d28af38a4bb57b Mon Sep 17 00:00:00 2001 From: Sly Gryphon Date: Wed, 17 Nov 2021 22:07:03 +1000 Subject: [PATCH 05/33] Add model creation option --- Examples/FactoryExample/Program.cs | 192 ++++++++++++++++++++--------- 1 file changed, 134 insertions(+), 58 deletions(-) diff --git a/Examples/FactoryExample/Program.cs b/Examples/FactoryExample/Program.cs index 25758fe..fdcb148 100644 --- a/Examples/FactoryExample/Program.cs +++ b/Examples/FactoryExample/Program.cs @@ -1,77 +1,153 @@ using System; +using System.Linq; +using System.Threading.Tasks; +using Azure; using FactoryExample.Devices; using FactoryExample.Models; using FactoryExample.Schema; +using Microsoft.Azure.DigitalTwins.Parser; +using Microsoft.Extensions.Configuration; using Telstra.Twins.Core; using Telstra.Twins.Services; -Console.WriteLine("Simple Digital Twin Serializer Example"); +Console.WriteLine("Digital Twin Code First Factory Example"); -var modelLibrary = new ModelLibrary(); -var serializer = new DigitalTwinSerializer(modelLibrary); +var configuration = new ConfigurationBuilder() + .AddJsonFile("appsettings.json", true) + .AddEnvironmentVariables() + .AddCommandLine(args) + .Build(); -Console.WriteLine("Models:"); -Console.WriteLine(); - -var modelTypes = new[] +var show = configuration.GetValue("show"); +if (!string.IsNullOrWhiteSpace(show)) { - typeof(Factory), typeof(FactoryFloor), typeof(ProductionLine), typeof(ProductionStep), - typeof(ProductionStepGrinding) -}; -foreach (var modelType in modelTypes) + switch (show.ToLowerInvariant()) + { + case "model": + var modelTypes = new[] + { + typeof(Factory), typeof(FactoryFloor), typeof(ProductionLine), typeof(ProductionStep), + typeof(ProductionStepGrinding) + }; + ShowModels(modelTypes); + return; + case "example": + ShowExamples(); + return; + } +} + +var create = configuration.GetValue("create"); +if (!string.IsNullOrWhiteSpace(create)) { - var modelDtdl = serializer.SerializeModel(modelType); - Console.WriteLine(modelDtdl); - Console.WriteLine(); + switch (create.ToLowerInvariant()) + { + case "model": + var modelTypes = new[] + { + typeof(Factory), typeof(FactoryFloor), typeof(ProductionLine), typeof(ProductionStep), + typeof(ProductionStepGrinding) + }; + await CreateModels(modelTypes); + return; + } } -Console.WriteLine("Twins:"); -Console.WriteLine(); +ShowHelp(); -var productionStepGrinding = new ProductionStepGrinding +async Task CreateModels(Type[] modelTypes) { - ChassisTemperature = 50, - FinalStep = false, - Force = 8.0, - GrindingTime = 30, - OperationStatus = ProductionStepStatus.Online, - PowerUsage = 100, - StartTime = new DateTimeOffset(2021, 11, 17, 19, 57, 0, TimeSpan.FromHours(10)), - StepId = "step1", - StepName = "GrindingStep" -}; - -var productionLine = new ProductionLine + var modelLibrary = new ModelLibrary(); + var serializer = new DigitalTwinSerializer(modelLibrary); + + var models = modelTypes.Select(x => serializer.SerializeModel(x)); + + // Validate + try + { + var parser = new ModelParser(); + var entityInfos = await parser.ParseAsync(models); + foreach (var kvp in entityInfos) + { + Console.WriteLine($"{kvp.Key} {kvp.Value}"); + } + } + catch (RequestFailedException ex) + { + Console.WriteLine($"Failed due to {ex}"); + } +} + +void ShowHelp() { - CurrentProductId = "production1", - LineId = "line1", - LineName = "ProductionLine", - LineOperationStatus = ProductionLineStatus.Online, - ProductBatchNumber = 5 -}; -productionLine.RunsSteps.Add(productionStepGrinding); - -var factoryFloor = new FactoryFloor + Console.WriteLine(" show model - shows the serialized model"); + Console.WriteLine(" show example - shows a serialized twin"); + Console.WriteLine(" create model - uploads the model"); +} + +void ShowModels(Type[] modelTypes) { - FloorId = "floor1", FloorName = "FactoryFloor", Temperature = 23, ComfortIndex = 0.8 -}; -factoryFloor.RunsLines.Add(productionLine); + var modelLibrary = new ModelLibrary(); + var serializer = new DigitalTwinSerializer(modelLibrary); -var factory = new Factory + foreach (var modelType in modelTypes) + { + var modelDtdl = serializer.SerializeModel(modelType); + Console.WriteLine(modelDtdl); + Console.WriteLine(); + } +} + +void ShowExamples() { - FactoryId = "factory1", - Country = "AU", - ZipCode = "4000", - FactoryName = "Chocolate Factory", - GeoLocation = new GeoCord { Latitude = -27.4705, Longitude = 153.026 }, - LastSupplyDate = new DateTimeOffset(2021, 11, 17, 18, 37, 0, TimeSpan.FromHours(10)) -}; -factory.Floors.Add(factoryFloor); - -var twin1Dtdl = serializer.SerializeTwin(factory); -Console.WriteLine(twin1Dtdl); -Console.WriteLine(); - -var twin2Dtdl = serializer.SerializeTwin(factory.Floors[0].RunsLines[0].RunsSteps[0]); -Console.WriteLine(twin2Dtdl); -Console.WriteLine(); + var modelLibrary = new ModelLibrary(); + var serializer = new DigitalTwinSerializer(modelLibrary); + + var productionStepGrinding = new ProductionStepGrinding + { + ChassisTemperature = 50, + FinalStep = false, + Force = 8.0, + GrindingTime = 30, + OperationStatus = ProductionStepStatus.Online, + PowerUsage = 100, + StartTime = new DateTimeOffset(2021, 11, 17, 19, 57, 0, TimeSpan.FromHours(10)), + StepId = "step1", + StepName = "GrindingStep" + }; + + var productionLine = new ProductionLine + { + CurrentProductId = "production1", + LineId = "line1", + LineName = "ProductionLine", + LineOperationStatus = ProductionLineStatus.Online, + ProductBatchNumber = 5 + }; + productionLine.RunsSteps.Add(productionStepGrinding); + + var factoryFloor = new FactoryFloor + { + FloorId = "floor1", FloorName = "FactoryFloor", Temperature = 23, ComfortIndex = 0.8 + }; + factoryFloor.RunsLines.Add(productionLine); + + var factory = new Factory + { + FactoryId = "factory1", + Country = "AU", + ZipCode = "4000", + FactoryName = "Chocolate Factory", + GeoLocation = new GeoCord { Latitude = -27.4705, Longitude = 153.026 }, + LastSupplyDate = new DateTimeOffset(2021, 11, 17, 18, 37, 0, TimeSpan.FromHours(10)) + }; + factory.Floors.Add(factoryFloor); + + var twin1Dtdl = serializer.SerializeTwin(factory); + Console.WriteLine(twin1Dtdl); + Console.WriteLine(); + + var twin2Dtdl = serializer.SerializeTwin(factory.Floors[0].RunsLines[0].RunsSteps[0]); + Console.WriteLine(twin2Dtdl); + Console.WriteLine(); +} From 0d60cf9dbd1d7c04ee187b95222e7fb4129dfd7e Mon Sep 17 00:00:00 2001 From: Sly Gryphon Date: Thu, 18 Nov 2021 01:10:49 +1000 Subject: [PATCH 06/33] Workarounds to get the parse happy with the output --- .../FactoryExample/Devices/ProductionStep.cs | 9 +++--- .../Devices/ProductionStepGrinding.cs | 15 ++++++---- Examples/FactoryExample/Models/Factory.cs | 7 +++-- .../FactoryExample/Models/FactoryFloor.cs | 6 ++-- .../FactoryExample/Models/ProductionLine.cs | 5 ++-- Examples/FactoryExample/Program.cs | 30 +++++++++++++------ 6 files changed, 47 insertions(+), 25 deletions(-) diff --git a/Examples/FactoryExample/Devices/ProductionStep.cs b/Examples/FactoryExample/Devices/ProductionStep.cs index 0aecf5c..9522fee 100644 --- a/Examples/FactoryExample/Devices/ProductionStep.cs +++ b/Examples/FactoryExample/Devices/ProductionStep.cs @@ -5,17 +5,18 @@ namespace FactoryExample.Devices { [DigitalTwin(Version = 1, DisplayName = "Factory Production Steps - Interface Model")] - public class ProductionStep : Device + public class ProductionStep : TwinBase { [TwinProperty] public bool FinalStep { get; set; } - [TwinProperty] public ProductionStepStatus OperationStatus { get; set; } + //[TwinProperty] public ProductionStepStatus OperationStatus { get; set; } - [TwinProperty] public DateTimeOffset? StartTime { get; set; } + //[TwinProperty] public DateTimeOffset? StartTime { get; set; } [TwinProperty] public string? StepId { get; set; } - [TwinRelationship(DisplayName = "Step Link")] + //[TwinRelationship(DisplayName = "Step Link")] + [TwinRelationship(MaxMultiplicity = 500)] public ProductionStep? StepLink { get; set; } [TwinProperty] public string? StepName { get; set; } diff --git a/Examples/FactoryExample/Devices/ProductionStepGrinding.cs b/Examples/FactoryExample/Devices/ProductionStepGrinding.cs index 480a0ee..0e82b8e 100644 --- a/Examples/FactoryExample/Devices/ProductionStepGrinding.cs +++ b/Examples/FactoryExample/Devices/ProductionStepGrinding.cs @@ -6,19 +6,24 @@ namespace FactoryExample.Devices ExtendsModelId = "dtmi:factoryexample:devices:productionstep;1")] public class ProductionStepGrinding : ProductionStep { - [TwinTelemetry(Unit = "degreeCelsius", SemanticType = "Temperature")] + //[TwinTelemetry(Unit = "degreeCelsius", SemanticType = "Temperature")] + [TwinTelemetry] public double? ChassisTemperature { get; set; } - [TwinTelemetry(Unit = "newton", SemanticType = "Force")] + //[TwinTelemetry(Unit = "newton", SemanticType = "Force")] + [TwinTelemetry] public double? Force { get; set; } - [TwinTelemetry(Unit = "minute", SemanticType = "TimeSpan")] + //[TwinTelemetry(Unit = "minute", SemanticType = "TimeSpan")] + [TwinTelemetry] public int? GrindingTime { get; set; } - [TwinTelemetry(Unit = "kilowatt", SemanticType = "Power")] + //[TwinTelemetry(Unit = "kilowatt", SemanticType = "Power")] + [TwinTelemetry] public double? PowerUsage { get; set; } - [TwinTelemetry(Unit = "hertz", SemanticType = "Frequency")] + //[TwinTelemetry(Unit = "hertz", SemanticType = "Frequency")] + [TwinTelemetry] public double? Vibration { get; set; } } } diff --git a/Examples/FactoryExample/Models/Factory.cs b/Examples/FactoryExample/Models/Factory.cs index a7fb5ba..bd2a905 100644 --- a/Examples/FactoryExample/Models/Factory.cs +++ b/Examples/FactoryExample/Models/Factory.cs @@ -14,13 +14,14 @@ public class Factory : TwinBase [TwinProperty] public string? FactoryId { get; set; } [TwinProperty] public string? FactoryName { get; set; } - - [TwinRelationship(DisplayName = "Has Floors")] + + //[TwinRelationship(DisplayName = "Has Floors")] + [TwinRelationship(MaxMultiplicity = 500)] public IList Floors { get; } = new List(); [TwinProperty] public GeoCord? GeoLocation { get; set; } - [TwinProperty] public DateTimeOffset LastSupplyDate { get; set; } + //[TwinProperty] public DateTimeOffset LastSupplyDate { get; set; } [TwinProperty] public string? ZipCode { get; set; } } diff --git a/Examples/FactoryExample/Models/FactoryFloor.cs b/Examples/FactoryExample/Models/FactoryFloor.cs index 6a72b92..2deffa9 100644 --- a/Examples/FactoryExample/Models/FactoryFloor.cs +++ b/Examples/FactoryExample/Models/FactoryFloor.cs @@ -13,10 +13,12 @@ public class FactoryFloor : TwinBase [TwinProperty] public string? FloorName { get; set; } - [TwinRelationship(DisplayName = "Runs Production Lines")] + //[TwinRelationship(DisplayName = "Runs Production Lines")] + [TwinRelationship(MaxMultiplicity = 500)] public IList RunsLines { get; } = new List(); - [TwinTelemetry(Unit = "degreeCelsius", SemanticType = "Temperature")] + //[TwinTelemetry(Unit = "degreeCelsius", SemanticType = "Temperature")] + [TwinTelemetry] public double? Temperature { get; set; } } } diff --git a/Examples/FactoryExample/Models/ProductionLine.cs b/Examples/FactoryExample/Models/ProductionLine.cs index e4a83a8..7eaef96 100644 --- a/Examples/FactoryExample/Models/ProductionLine.cs +++ b/Examples/FactoryExample/Models/ProductionLine.cs @@ -14,11 +14,12 @@ public class ProductionLine : TwinBase [TwinProperty] public string? LineName { get; set; } - [TwinProperty] public ProductionLineStatus LineOperationStatus { get; set; } + //[TwinProperty] public ProductionLineStatus LineOperationStatus { get; set; } [TwinProperty] public int? ProductBatchNumber { get; set; } - [TwinRelationship(DisplayName = "Runs Steps")] + //[TwinRelationship(DisplayName = "Runs Steps")] + [TwinRelationship(MaxMultiplicity = 500)] public IList RunsSteps { get; } = new List(); } } diff --git a/Examples/FactoryExample/Program.cs b/Examples/FactoryExample/Program.cs index fdcb148..23bc523 100644 --- a/Examples/FactoryExample/Program.cs +++ b/Examples/FactoryExample/Program.cs @@ -5,6 +5,7 @@ using FactoryExample.Devices; using FactoryExample.Models; using FactoryExample.Schema; +using Microsoft.AspNetCore.Mvc.ApplicationModels; using Microsoft.Azure.DigitalTwins.Parser; using Microsoft.Extensions.Configuration; using Telstra.Twins.Core; @@ -67,22 +68,33 @@ async Task CreateModels(Type[] modelTypes) { var parser = new ModelParser(); var entityInfos = await parser.ParseAsync(models); + Console.WriteLine($"PARSE RESULTS:"); foreach (var kvp in entityInfos) { - Console.WriteLine($"{kvp.Key} {kvp.Value}"); + Console.WriteLine($"[{kvp.Key}] = {kvp.Value.EntityKind} {kvp.Value.Id} ({kvp.Value.DisplayName.FirstOrDefault().Value})"); + } + } + catch (ParsingException ex) + { + Console.WriteLine($"PARSE FAILED: {ex.Message}"); + Console.WriteLine($"ERRORS:"); + var count = 0; + foreach (var error in ex.Errors) + { + Console.WriteLine($"{++count}. {error}"); } } catch (RequestFailedException ex) { - Console.WriteLine($"Failed due to {ex}"); + Console.WriteLine($"REQUEST FAILED: {ex.Message}"); } } void ShowHelp() { - Console.WriteLine(" show model - shows the serialized model"); - Console.WriteLine(" show example - shows a serialized twin"); - Console.WriteLine(" create model - uploads the model"); + Console.WriteLine(" --show model : shows the serialized model"); + Console.WriteLine(" --show example : shows a serialized twin"); + Console.WriteLine(" --create model : validate and uploads the model"); } void ShowModels(Type[] modelTypes) @@ -109,9 +121,9 @@ void ShowExamples() FinalStep = false, Force = 8.0, GrindingTime = 30, - OperationStatus = ProductionStepStatus.Online, + //OperationStatus = ProductionStepStatus.Online, PowerUsage = 100, - StartTime = new DateTimeOffset(2021, 11, 17, 19, 57, 0, TimeSpan.FromHours(10)), + //StartTime = new DateTimeOffset(2021, 11, 17, 19, 57, 0, TimeSpan.FromHours(10)), StepId = "step1", StepName = "GrindingStep" }; @@ -121,7 +133,7 @@ void ShowExamples() CurrentProductId = "production1", LineId = "line1", LineName = "ProductionLine", - LineOperationStatus = ProductionLineStatus.Online, + //LineOperationStatus = ProductionLineStatus.Online, ProductBatchNumber = 5 }; productionLine.RunsSteps.Add(productionStepGrinding); @@ -139,7 +151,7 @@ void ShowExamples() ZipCode = "4000", FactoryName = "Chocolate Factory", GeoLocation = new GeoCord { Latitude = -27.4705, Longitude = 153.026 }, - LastSupplyDate = new DateTimeOffset(2021, 11, 17, 18, 37, 0, TimeSpan.FromHours(10)) + //LastSupplyDate = new DateTimeOffset(2021, 11, 17, 18, 37, 0, TimeSpan.FromHours(10)) }; factory.Floors.Add(factoryFloor); From d64d8c16b2ffd68800ef202aefa1c9a813b1a991 Mon Sep 17 00:00:00 2001 From: Sly Gryphon Date: Fri, 26 Nov 2021 10:38:48 +1000 Subject: [PATCH 07/33] WIP - deploy using Azure PowerShell --- .../FactoryExample/deploy-infrastructure.ps1 | 65 +++++++++++++++++++ .../FactoryExample/remove-infrastructure.ps1 | 32 +++++++++ 2 files changed, 97 insertions(+) create mode 100644 Examples/FactoryExample/deploy-infrastructure.ps1 create mode 100644 Examples/FactoryExample/remove-infrastructure.ps1 diff --git a/Examples/FactoryExample/deploy-infrastructure.ps1 b/Examples/FactoryExample/deploy-infrastructure.ps1 new file mode 100644 index 0000000..c063d06 --- /dev/null +++ b/Examples/FactoryExample/deploy-infrastructure.ps1 @@ -0,0 +1,65 @@ +#!/usr/bin/env pwsh +[CmdletBinding()] +param ( + [string]$SubscriptionId = $null, + [string]$AppName = 'codefirsttwins', + [string]$Environment = 'demo', + [string]$Location = 'australiaeast' +) + +# Pre-requisites: +# +# Running these scripts requires the following to be installed: +# * PowerShell, https://github.com/PowerShell/PowerShell +# * Azure PowerShell module, https://docs.microsoft.com/en-us/powershell/azure/install-az-ps +# Install-Module -Name Az -Scope CurrentUser -Force +# * Azure Digital Twins module (preview installed separately) +# Install-Module -Name Az.DigitalTwins -Scope CurrentUser -Force +# Register-AzResourceProvider -ProviderNamespace Microsoft.DigitalTwins +# +# You also need to authenticate with: Connect-AzAccount +# +# To see messages, set verbose preference before running: +# $VerbosePreference = 'Continue' +# ./deploy-infrastructure.ps1 + +$ErrorActionPreference="Stop" + +if ($SubscriptionId) { + Write-Verbose "Setting context to subscription ID $SubscriptionId" + Set-AzContext -SubscriptionId $SubscriptionId +} else { + $SubscriptionId = (Get-AzContext).Subscription + Write-Verbose "Using existing context subscription ID $SubscriptionId" +} + + +# Following standard naming conventions from Azure Cloud Adoption Framework +# https://docs.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/resource-naming + +# Include an abbreviated organsiation identifier (after app name) in global names to make them unique +$OrgId = "org$($SubscriptionId.Substring(0,4))" + +$ResourceGroupName = "rg-$AppName-$Environment-001" +$DigitalTwinsName = "dt-$AppName-$OrgId-$Environment" +$IotHubName = "iot-$AppName-$OrgId-$Environment" + +# Following standard tagging conventions from Azure Cloud Adoption Framework +# https://docs.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/resource-tagging + +$Tag = @{ WorkloadName = 'codefirsttwins'; DataClassification = 'Non-business'; Criticality = 'Low'; + BusinessUnit = 'Demo'; ApplicationName = $AppName; Env = $Environment } + +# Create + +New-AzResourceGroup -Name $ResourceGroupName -Location $Location -Tag $Tag -Force + +New-AzDigitalTwinsInstance -ResourceGroupName $ResourceGroupName -ResourceName $DigitalTwinsName -Location $Location -Tag $Tag + +New-AzIotHub -ResourceGroupName $ResourceGroupName -Name $IotHubName -SkuName S1 -Units 1 -Location $Location -Tag $Tag + +# Output + +(Get-AzDigitalTwinsInstance -ResourceGroupName $ResourceGroupName -ResourceName $DigitalTwinsName).HostName +(Get-AzIotHub $ResourceGroupName).Properties.HostName + diff --git a/Examples/FactoryExample/remove-infrastructure.ps1 b/Examples/FactoryExample/remove-infrastructure.ps1 new file mode 100644 index 0000000..f440f58 --- /dev/null +++ b/Examples/FactoryExample/remove-infrastructure.ps1 @@ -0,0 +1,32 @@ +[CmdletBinding()] +param ( + [string]$SubscriptionId = $null, + [string]$AppName = 'codefirsttwins', + [string]$Environment = 'demo' +) + +# Pre-requisites: +# +# Running these scripts requires the following to be installed: +# * PowerShell, https://github.com/PowerShell/PowerShell +# * Azure CLI, https://docs.microsoft.com/en-us/cli/azure +# +# You also need to run `az login` to authenticate +# +# To see messages, set verbose preference before running: +# $VerbosePreference = 'Continue' +# ./deploy-infrastructure.ps1 + +$ErrorActionPreference="Stop" + +if (-not $SubscriptionId) { + Write-Verbose "Using default subscription ID" + $SubscriptionId = (ConvertFrom-Json "$(az account show)").id +} + +$AppName = 'codefirsttwins' +$Environment = 'demo' + +$ResourceGroupName = "rg-$AppName-$Environment-001" + +Remove-AzResourceGroup -Name $ResourceGroupName From 4eb1b6fe46e7a6c4d82b73d7748aa1c8f117f780 Mon Sep 17 00:00:00 2001 From: Sly Gryphon Date: Tue, 30 Nov 2021 20:01:13 +1000 Subject: [PATCH 08/33] WIP - script stuff --- Examples/FactoryExample/ReadMe.md | 36 +++++++++++ .../deploy-infrastructure-azcli.ps1 | 64 +++++++++++++++++++ .../FactoryExample/deploy-infrastructure.ps1 | 5 +- 3 files changed, 102 insertions(+), 3 deletions(-) create mode 100644 Examples/FactoryExample/ReadMe.md create mode 100644 Examples/FactoryExample/deploy-infrastructure-azcli.ps1 diff --git a/Examples/FactoryExample/ReadMe.md b/Examples/FactoryExample/ReadMe.md new file mode 100644 index 0000000..9b23c30 --- /dev/null +++ b/Examples/FactoryExample/ReadMe.md @@ -0,0 +1,36 @@ +Code First Azure Digital Twins -- End to end example +==================================================== + +Requirements: + +* dotnet (3.1 LTS or higher) +* PowerShell (7.0 LTS or higher) + +Based on https://github.com/Azure-Samples/digital-twins-samples/tree/master/HandsOnLab + + +```pwsh +az login +az account set --subscription "" +``` + + +``` +az group create --location --name +az dt create --dt-name --resource-group --location +az dt show --dt-name . + +az iot hub create --name --resource-group --sku S1 +``` + + + +``` +Set-AzContext -SubscriptionId 00000000-0000-0000-0000-000000000000 +Register-AzResourceProvider -ProviderNamespace Microsoft.DigitalTwins +Install-Module -Name Az.DigitalTwins +New-AzResourceGroup -Name -Location +New-AzDigitalTwinsInstance -ResourceGroupName -ResourceName -Location +Get-AzDigitalTwinsInstance -ResourceGroupName -ResourceName | + Select-Object -Property * + diff --git a/Examples/FactoryExample/deploy-infrastructure-azcli.ps1 b/Examples/FactoryExample/deploy-infrastructure-azcli.ps1 new file mode 100644 index 0000000..8678403 --- /dev/null +++ b/Examples/FactoryExample/deploy-infrastructure-azcli.ps1 @@ -0,0 +1,64 @@ +#!/usr/bin/env pwsh +[CmdletBinding()] +param ( + [string]$SubscriptionId = $null, + [string]$AppName = 'codefirsttwins', + [string]$Environment = 'demo', + [string]$Location = 'australiaeast' +) + +# Pre-requisites: +# +# Running these scripts requires the following to be installed: +# * PowerShell, https://github.com/PowerShell/PowerShell +# * Azure CLI, https://docs.microsoft.com/en-us/cli/azure +# * IoT Extension for Azure CLI: +# az extension add --upgrade --name azure-iot +# az provider register --namespace 'Microsoft.DigitalTwins' +# +# You also need to run `az login` to authenticate +# +# To see messages, set verbose preference before running: +# $VerbosePreference = 'Continue' +# ./deploy-infrastructure.ps1 + +$ErrorActionPreference="Stop" + +if (-not $SubscriptionId) { + Write-Verbose "Using default subscription ID" + $SubscriptionId = (ConvertFrom-Json "$(az account show)").id +} + +# Following standard naming conventions from Azure Cloud Adoption Framework +# https://docs.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/resource-naming + +# Include an subscription or organisation identifier (after app name) in global names to make them unique +$OrgId = "x$($SubscriptionId.Substring(0,4))" + +$ResourceGroupName = "rg-$AppName-$Environment-001" +$DigitalTwinsName = "dt-$AppName-$OrgId-$Environment" +$IotHubName = "iot-$AppName-$OrgId-$Environment" + +# Following standard tagging conventions from Azure Cloud Adoption Framework +# https://docs.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/resource-tagging + +$Tag = @{ WorkloadName = 'codefirsttwins'; DataClassification = 'Non-business'; Criticality = 'Low'; + BusinessUnit = 'Demo'; ApplicationName = $AppName; Env = $Environment } + +# Create + +az group create -g $ResourceGroupName -l $Location --subscription $SubscriptionId ` + --tags "WorkloadName=$($Tag.WorkloadName)" "DataClassification=$($Tag.DataClassification)" "Criticality=$($Tag.Criticality)" ` + "BusinessUnit=$($Tag.BusinessUnit)" "ApplicationName=$($Tag.ApplicationName)" "Env=$($Tag.Env)" + +az dt create --dt-name $DigitalTwinsName --resource-group $ResourceGroupName --location $Location ` + --tags "WorkloadName=$($Tag.WorkloadName)" "DataClassification=$($Tag.DataClassification)" "Criticality=$($Tag.Criticality)" ` + "BusinessUnit=$($Tag.BusinessUnit)" "ApplicationName=$($Tag.ApplicationName)" "Env=$($Tag.Env)" + +az iot hub create --name $IotHubName --resource-group $ResourceGroupName --sku S1 ` + --tags "WorkloadName=$($Tag.WorkloadName)" "DataClassification=$($Tag.DataClassification)" "Criticality=$($Tag.Criticality)" ` + "BusinessUnit=$($Tag.BusinessUnit)" "ApplicationName=$($Tag.ApplicationName)" "Env=$($Tag.Env)" + +# Output + +az dt show --dt-name $DigitalTwinsName diff --git a/Examples/FactoryExample/deploy-infrastructure.ps1 b/Examples/FactoryExample/deploy-infrastructure.ps1 index c063d06..f21daa3 100644 --- a/Examples/FactoryExample/deploy-infrastructure.ps1 +++ b/Examples/FactoryExample/deploy-infrastructure.ps1 @@ -33,12 +33,11 @@ if ($SubscriptionId) { Write-Verbose "Using existing context subscription ID $SubscriptionId" } - # Following standard naming conventions from Azure Cloud Adoption Framework # https://docs.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/resource-naming -# Include an abbreviated organsiation identifier (after app name) in global names to make them unique -$OrgId = "org$($SubscriptionId.Substring(0,4))" +# Include an subscription or organisation identifier (after app name) in global names to make them unique +$OrgId = "x$($SubscriptionId.Substring(0,4))" $ResourceGroupName = "rg-$AppName-$Environment-001" $DigitalTwinsName = "dt-$AppName-$OrgId-$Environment" From ce8e8780acb8306ee9742e2eec2210b1af1adc13 Mon Sep 17 00:00:00 2001 From: Sly Gryphon Date: Tue, 30 Nov 2021 22:07:54 +1000 Subject: [PATCH 09/33] Fix for deploy script --- Examples/FactoryExample/deploy-infrastructure.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Examples/FactoryExample/deploy-infrastructure.ps1 b/Examples/FactoryExample/deploy-infrastructure.ps1 index f21daa3..1f1d0c4 100644 --- a/Examples/FactoryExample/deploy-infrastructure.ps1 +++ b/Examples/FactoryExample/deploy-infrastructure.ps1 @@ -29,7 +29,7 @@ if ($SubscriptionId) { Write-Verbose "Setting context to subscription ID $SubscriptionId" Set-AzContext -SubscriptionId $SubscriptionId } else { - $SubscriptionId = (Get-AzContext).Subscription + $SubscriptionId = (Get-AzContext).Subscription.Id Write-Verbose "Using existing context subscription ID $SubscriptionId" } From 0932938fbee7c039a151701581f357195d30062e Mon Sep 17 00:00:00 2001 From: Sly Gryphon Date: Tue, 30 Nov 2021 23:23:56 +1000 Subject: [PATCH 10/33] Update org id in scripts --- Examples/FactoryExample/deploy-infrastructure-azcli.ps1 | 2 +- Examples/FactoryExample/deploy-infrastructure.ps1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Examples/FactoryExample/deploy-infrastructure-azcli.ps1 b/Examples/FactoryExample/deploy-infrastructure-azcli.ps1 index 8678403..e9c7794 100644 --- a/Examples/FactoryExample/deploy-infrastructure-azcli.ps1 +++ b/Examples/FactoryExample/deploy-infrastructure-azcli.ps1 @@ -33,7 +33,7 @@ if (-not $SubscriptionId) { # https://docs.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/resource-naming # Include an subscription or organisation identifier (after app name) in global names to make them unique -$OrgId = "x$($SubscriptionId.Substring(0,4))" +$OrgId = "0x$($SubscriptionId.Substring(0,4))" $ResourceGroupName = "rg-$AppName-$Environment-001" $DigitalTwinsName = "dt-$AppName-$OrgId-$Environment" diff --git a/Examples/FactoryExample/deploy-infrastructure.ps1 b/Examples/FactoryExample/deploy-infrastructure.ps1 index 1f1d0c4..17708c0 100644 --- a/Examples/FactoryExample/deploy-infrastructure.ps1 +++ b/Examples/FactoryExample/deploy-infrastructure.ps1 @@ -37,7 +37,7 @@ if ($SubscriptionId) { # https://docs.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/resource-naming # Include an subscription or organisation identifier (after app name) in global names to make them unique -$OrgId = "x$($SubscriptionId.Substring(0,4))" +$OrgId = "0x$($SubscriptionId.Substring(0,4))" $ResourceGroupName = "rg-$AppName-$Environment-001" $DigitalTwinsName = "dt-$AppName-$OrgId-$Environment" From 7abdfb5441ada2d7a5e9fa70ea78dbd6e055f32d Mon Sep 17 00:00:00 2001 From: Sly Gryphon Date: Tue, 30 Nov 2021 23:24:29 +1000 Subject: [PATCH 11/33] Initial exported arm & bicep files --- .../rg-codefirsttwins-demo-001.json | 113 ++++++++++++++++++ .../rg-codefirsttwins-demo-001.bicep | 97 +++++++++++++++ 2 files changed, 210 insertions(+) create mode 100644 Examples/FactoryExample/infrastructure-arm/rg-codefirsttwins-demo-001.json create mode 100644 Examples/FactoryExample/infrastructure/rg-codefirsttwins-demo-001.bicep diff --git a/Examples/FactoryExample/infrastructure-arm/rg-codefirsttwins-demo-001.json b/Examples/FactoryExample/infrastructure-arm/rg-codefirsttwins-demo-001.json new file mode 100644 index 0000000..c37c76d --- /dev/null +++ b/Examples/FactoryExample/infrastructure-arm/rg-codefirsttwins-demo-001.json @@ -0,0 +1,113 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "IotHubs_iot_codefirsttwins_0xacc5_demo_connectionString": { + "type": "SecureString" + }, + "IotHubs_iot_codefirsttwins_0xacc5_demo_containerName": { + "type": "SecureString" + }, + "IotHubs_iot_codefirsttwins_0xacc5_demo_name": { + "type": "String" + }, + "digitalTwinsInstances_dt_codefirsttwins_0xacc5_demo_name": { + "type": "String" + } + }, + "variables": {}, + "resources": [ + { + "type": "Microsoft.Devices/IotHubs", + "apiVersion": "2021-07-01", + "name": "[parameters('IotHubs_iot_codefirsttwins_0xacc5_demo_name')]", + "location": "australiaeast", + "tags": { + "ApplicationName": "codefirsttwins", + "WorkloadName": "codefirsttwins", + "DataClassification": "Non-business", + "Criticality": "Low", + "BusinessUnit": "Demo", + "Env": "demo" + }, + "sku": { + "name": "S1", + "tier": "Standard", + "capacity": 1 + }, + "identity": { + "type": "None" + }, + "properties": { + "ipFilterRules": [], + "eventHubEndpoints": { + "events": { + "retentionTimeInDays": 1, + "partitionCount": 4 + } + }, + "routing": { + "endpoints": { + "serviceBusQueues": [], + "serviceBusTopics": [], + "eventHubs": [], + "storageContainers": [] + }, + "routes": [], + "fallbackRoute": { + "name": "$fallback", + "source": "DeviceMessages", + "condition": "true", + "endpointNames": [ + "events" + ], + "isEnabled": true + } + }, + "storageEndpoints": { + "$default": { + "sasTtlAsIso8601": "PT1H", + "connectionString": "[parameters('IotHubs_iot_codefirsttwins_0xacc5_demo_connectionString')]", + "containerName": "[parameters('IotHubs_iot_codefirsttwins_0xacc5_demo_containerName')]" + } + }, + "messagingEndpoints": { + "fileNotifications": { + "lockDurationAsIso8601": "PT1M", + "ttlAsIso8601": "PT1H", + "maxDeliveryCount": 10 + } + }, + "enableFileUploadNotifications": false, + "cloudToDevice": { + "maxDeliveryCount": 10, + "defaultTtlAsIso8601": "PT1H", + "feedback": { + "lockDurationAsIso8601": "PT1M", + "ttlAsIso8601": "PT1H", + "maxDeliveryCount": 10 + } + }, + "features": "None" + } + }, + { + "type": "Microsoft.DigitalTwins/digitalTwinsInstances", + "apiVersion": "2020-12-01", + "name": "[parameters('digitalTwinsInstances_dt_codefirsttwins_0xacc5_demo_name')]", + "location": "australiaeast", + "tags": { + "ApplicationName": "codefirsttwins", + "WorkloadName": "codefirsttwins", + "DataClassification": "Non-business", + "Criticality": "Low", + "BusinessUnit": "Demo", + "Env": "demo" + }, + "properties": { + "privateEndpointConnections": [], + "publicNetworkAccess": "Enabled" + } + } + ] +} \ No newline at end of file diff --git a/Examples/FactoryExample/infrastructure/rg-codefirsttwins-demo-001.bicep b/Examples/FactoryExample/infrastructure/rg-codefirsttwins-demo-001.bicep new file mode 100644 index 0000000..1531a08 --- /dev/null +++ b/Examples/FactoryExample/infrastructure/rg-codefirsttwins-demo-001.bicep @@ -0,0 +1,97 @@ +@secure() +param IotHubs_iot_codefirsttwins_0xacc5_demo_connectionString string + +@secure() +param IotHubs_iot_codefirsttwins_0xacc5_demo_containerName string +param IotHubs_iot_codefirsttwins_0xacc5_demo_name string +param digitalTwinsInstances_dt_codefirsttwins_0xacc5_demo_name string + +resource IotHubs_iot_codefirsttwins_0xacc5_demo_name_resource 'Microsoft.Devices/IotHubs@2021-07-01' = { + name: IotHubs_iot_codefirsttwins_0xacc5_demo_name + location: 'australiaeast' + tags: { + ApplicationName: 'codefirsttwins' + WorkloadName: 'codefirsttwins' + DataClassification: 'Non-business' + Criticality: 'Low' + BusinessUnit: 'Demo' + Env: 'demo' + } + sku: { + name: 'S1' + tier: 'Standard' + capacity: 1 + } + identity: { + type: 'None' + } + properties: { + ipFilterRules: [] + eventHubEndpoints: { + events: { + retentionTimeInDays: 1 + partitionCount: 4 + } + } + routing: { + endpoints: { + serviceBusQueues: [] + serviceBusTopics: [] + eventHubs: [] + storageContainers: [] + } + routes: [] + fallbackRoute: { + name: '$fallback' + source: 'DeviceMessages' + condition: 'true' + endpointNames: [ + 'events' + ] + isEnabled: true + } + } + storageEndpoints: { + '$default': { + sasTtlAsIso8601: 'PT1H' + connectionString: IotHubs_iot_codefirsttwins_0xacc5_demo_connectionString + containerName: IotHubs_iot_codefirsttwins_0xacc5_demo_containerName + } + } + messagingEndpoints: { + fileNotifications: { + lockDurationAsIso8601: 'PT1M' + ttlAsIso8601: 'PT1H' + maxDeliveryCount: 10 + } + } + enableFileUploadNotifications: false + cloudToDevice: { + maxDeliveryCount: 10 + defaultTtlAsIso8601: 'PT1H' + feedback: { + lockDurationAsIso8601: 'PT1M' + ttlAsIso8601: 'PT1H' + maxDeliveryCount: 10 + } + } + features: 'None' + } +} + +resource digitalTwinsInstances_dt_codefirsttwins_0xacc5_demo_name_resource 'Microsoft.DigitalTwins/digitalTwinsInstances@2020-12-01' = { + name: digitalTwinsInstances_dt_codefirsttwins_0xacc5_demo_name + location: 'australiaeast' + tags: { + ApplicationName: 'codefirsttwins' + WorkloadName: 'codefirsttwins' + DataClassification: 'Non-business' + Criticality: 'Low' + BusinessUnit: 'Demo' + Env: 'demo' + } + properties: { + privateEndpointConnections: [] + publicNetworkAccess: 'Enabled' + } +} \ No newline at end of file From 72796690ed386431ff674557a74a5f8a93c48f40 Mon Sep 17 00:00:00 2001 From: Sly Gryphon Date: Wed, 1 Dec 2021 07:47:29 +1000 Subject: [PATCH 12/33] Working (but weird) ARM template --- .../rg-codefirsttwins-demo-001.json | 57 +++++++++++-------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/Examples/FactoryExample/infrastructure-arm/rg-codefirsttwins-demo-001.json b/Examples/FactoryExample/infrastructure-arm/rg-codefirsttwins-demo-001.json index c37c76d..4e1b898 100644 --- a/Examples/FactoryExample/infrastructure-arm/rg-codefirsttwins-demo-001.json +++ b/Examples/FactoryExample/infrastructure-arm/rg-codefirsttwins-demo-001.json @@ -1,35 +1,49 @@ +// Connect-AzAccount +// Set-AzContext -Subscription +// New-AzResourceGroupDeployment -ResourceGroupName 'rg-codefirsttwins-demo-001' -TemplateFile 'rg-codefirsttwins-demo-001.json' -TemplateParameterObject @{ OrgId = "0x$((Get-AzContext).Subscription.Id.Substring(0,4))" } { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { + "AppName": { + "type": "String", + "defaultValue": "codefirsttwins" + }, + "Environment": { + "type": "String", + "defaultValue": "demo" + }, + "Location": { + "type": "String", + "defaultValue": "australiaeast" + }, + "OrgId": { + "type": "String" + }, "IotHubs_iot_codefirsttwins_0xacc5_demo_connectionString": { "type": "SecureString" }, "IotHubs_iot_codefirsttwins_0xacc5_demo_containerName": { "type": "SecureString" - }, - "IotHubs_iot_codefirsttwins_0xacc5_demo_name": { - "type": "String" - }, - "digitalTwinsInstances_dt_codefirsttwins_0xacc5_demo_name": { - "type": "String" } }, - "variables": {}, + "variables": { + "tags": { + "ApplicationName": "[parameters('AppName')]", + "WorkloadName": "codefirsttwins", + "DataClassification": "Non-business", + "Criticality": "Low", + "BusinessUnit": "Demo", + "Env": "[parameters('Environment')]" + } + }, "resources": [ { "type": "Microsoft.Devices/IotHubs", "apiVersion": "2021-07-01", - "name": "[parameters('IotHubs_iot_codefirsttwins_0xacc5_demo_name')]", + "name": "[concat('iot-',parameters('AppName'),'-',parameters('OrgId'),'-',parameters('Environment'))]", "location": "australiaeast", - "tags": { - "ApplicationName": "codefirsttwins", - "WorkloadName": "codefirsttwins", - "DataClassification": "Non-business", - "Criticality": "Low", - "BusinessUnit": "Demo", - "Env": "demo" - }, + "tags": "[variables('tags')]", "sku": { "name": "S1", "tier": "Standard", @@ -94,16 +108,9 @@ { "type": "Microsoft.DigitalTwins/digitalTwinsInstances", "apiVersion": "2020-12-01", - "name": "[parameters('digitalTwinsInstances_dt_codefirsttwins_0xacc5_demo_name')]", + "name": "[concat('dt-',parameters('AppName'),'-',parameters('OrgId'),'-',parameters('Environment'))]", "location": "australiaeast", - "tags": { - "ApplicationName": "codefirsttwins", - "WorkloadName": "codefirsttwins", - "DataClassification": "Non-business", - "Criticality": "Low", - "BusinessUnit": "Demo", - "Env": "demo" - }, + "tags": "[variables('tags')]", "properties": { "privateEndpointConnections": [], "publicNetworkAccess": "Enabled" From 20b81c9e3a3c70f47b2e2c15678a405fc640ab7a Mon Sep 17 00:00:00 2001 From: Sly Gryphon Date: Wed, 1 Dec 2021 08:39:55 +1000 Subject: [PATCH 13/33] Cleanup ARM example --- .../rg-codefirsttwins-demo-001.json | 141 +++++++----------- 1 file changed, 53 insertions(+), 88 deletions(-) diff --git a/Examples/FactoryExample/infrastructure-arm/rg-codefirsttwins-demo-001.json b/Examples/FactoryExample/infrastructure-arm/rg-codefirsttwins-demo-001.json index 4e1b898..cf867f0 100644 --- a/Examples/FactoryExample/infrastructure-arm/rg-codefirsttwins-demo-001.json +++ b/Examples/FactoryExample/infrastructure-arm/rg-codefirsttwins-demo-001.json @@ -1,119 +1,84 @@ // Connect-AzAccount // Set-AzContext -Subscription -// New-AzResourceGroupDeployment -ResourceGroupName 'rg-codefirsttwins-demo-001' -TemplateFile 'rg-codefirsttwins-demo-001.json' -TemplateParameterObject @{ OrgId = "0x$((Get-AzContext).Subscription.Id.Substring(0,4))" } +// New-AzDeployment -Location 'australiaeast' -TemplateFile 'infrastructure-arm/rg-codefirsttwins-demo-001.json' { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { - "AppName": { + "appName": { "type": "String", "defaultValue": "codefirsttwins" }, - "Environment": { + "environment": { "type": "String", "defaultValue": "demo" }, - "Location": { + "location": { "type": "String", - "defaultValue": "australiaeast" + "defaultValue": "[deployment().location]" }, - "OrgId": { - "type": "String" - }, - "IotHubs_iot_codefirsttwins_0xacc5_demo_connectionString": { - "type": "SecureString" - }, - "IotHubs_iot_codefirsttwins_0xacc5_demo_containerName": { - "type": "SecureString" + "orgId": { + "type": "String", + "defaultValue": "[concat('0x',substring(subscription().subscriptionId, 0, 4))]" } }, "variables": { "tags": { - "ApplicationName": "[parameters('AppName')]", + "ApplicationName": "[parameters('appName')]", "WorkloadName": "codefirsttwins", "DataClassification": "Non-business", "Criticality": "Low", "BusinessUnit": "Demo", - "Env": "[parameters('Environment')]" - } + "Env": "[parameters('environment')]" + }, + "rgName": "[concat('rg-',parameters('appName'),'-',parameters('environment'),'-001')]" }, "resources": [ { - "type": "Microsoft.Devices/IotHubs", - "apiVersion": "2021-07-01", - "name": "[concat('iot-',parameters('AppName'),'-',parameters('OrgId'),'-',parameters('Environment'))]", - "location": "australiaeast", + "type": "Microsoft.Resources/resourceGroups", + "apiVersion": "2021-04-01", + "name": "[variables('rgName')]", + "location": "[parameters('location')]", "tags": "[variables('tags')]", - "sku": { - "name": "S1", - "tier": "Standard", - "capacity": 1 - }, - "identity": { - "type": "None" - }, - "properties": { - "ipFilterRules": [], - "eventHubEndpoints": { - "events": { - "retentionTimeInDays": 1, - "partitionCount": 4 - } - }, - "routing": { - "endpoints": { - "serviceBusQueues": [], - "serviceBusTopics": [], - "eventHubs": [], - "storageContainers": [] - }, - "routes": [], - "fallbackRoute": { - "name": "$fallback", - "source": "DeviceMessages", - "condition": "true", - "endpointNames": [ - "events" - ], - "isEnabled": true - } - }, - "storageEndpoints": { - "$default": { - "sasTtlAsIso8601": "PT1H", - "connectionString": "[parameters('IotHubs_iot_codefirsttwins_0xacc5_demo_connectionString')]", - "containerName": "[parameters('IotHubs_iot_codefirsttwins_0xacc5_demo_containerName')]" - } - }, - "messagingEndpoints": { - "fileNotifications": { - "lockDurationAsIso8601": "PT1M", - "ttlAsIso8601": "PT1H", - "maxDeliveryCount": 10 - } - }, - "enableFileUploadNotifications": false, - "cloudToDevice": { - "maxDeliveryCount": 10, - "defaultTtlAsIso8601": "PT1H", - "feedback": { - "lockDurationAsIso8601": "PT1M", - "ttlAsIso8601": "PT1H", - "maxDeliveryCount": 10 - } - }, - "features": "None" - } + "properties": {} }, { - "type": "Microsoft.DigitalTwins/digitalTwinsInstances", - "apiVersion": "2020-12-01", - "name": "[concat('dt-',parameters('AppName'),'-',parameters('OrgId'),'-',parameters('Environment'))]", - "location": "australiaeast", - "tags": "[variables('tags')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2021-04-01", + "name": "demoDeployment", + "resourceGroup": "[variables('rgName')]", + "dependsOn": [ + "[resourceId('Microsoft.Resources/resourceGroups/', variables('rgName'))]" + ], "properties": { - "privateEndpointConnections": [], - "publicNetworkAccess": "Enabled" + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.Devices/IotHubs", + "apiVersion": "2021-07-01", + "name": "[concat('iot-',parameters('appName'),'-',parameters('orgId'),'-',parameters('environment'))]", + "location": "[parameters('location')]", + "tags": "[variables('tags')]", + "sku": { + "name": "S1", + "tier": "Standard", + "capacity": 1 + } + }, + { + "type": "Microsoft.DigitalTwins/digitalTwinsInstances", + "apiVersion": "2020-12-01", + "name": "[concat('dt-',parameters('appName'),'-',parameters('orgId'),'-',parameters('environment'))]", + "location": "[parameters('location')]", + "tags": "[variables('tags')]" + } + ] + } } } ] From 05cd72dceccae16ab6b9f88bdd833548ab98e38d Mon Sep 17 00:00:00 2001 From: Sly Gryphon Date: Thu, 2 Dec 2021 07:14:18 +1000 Subject: [PATCH 14/33] Update bicep example --- .../demoDeployment-module.bicep | 26 +++++ .../FactoryExample/infrastructure/main.bicep | 42 ++++++++ .../rg-codefirsttwins-demo-001.bicep | 97 ------------------- 3 files changed, 68 insertions(+), 97 deletions(-) create mode 100644 Examples/FactoryExample/infrastructure/demoDeployment-module.bicep create mode 100644 Examples/FactoryExample/infrastructure/main.bicep delete mode 100644 Examples/FactoryExample/infrastructure/rg-codefirsttwins-demo-001.bicep diff --git a/Examples/FactoryExample/infrastructure/demoDeployment-module.bicep b/Examples/FactoryExample/infrastructure/demoDeployment-module.bicep new file mode 100644 index 0000000..cd57707 --- /dev/null +++ b/Examples/FactoryExample/infrastructure/demoDeployment-module.bicep @@ -0,0 +1,26 @@ +// Module for deploying resource group items (default target scope) + +param appName string +param orgId string +param environment string +param tags object + +var location = resourceGroup().location +var iotHubName = 'iot-${appName}-${orgId}-${environment}' +var digitalTwinsName = 'dt-${appName}-${orgId}-${environment}' + +resource iot_appName_orgId_environment 'Microsoft.Devices/IotHubs@2021-07-01' = { + name: iotHubName + location: location + tags: tags + sku: { + name: 'S1' + capacity: 1 + } +} + +resource dt_appName_orgId_environment 'Microsoft.DigitalTwins/digitalTwinsInstances@2020-12-01' = { + name: digitalTwinsName + location: location + tags: tags +} \ No newline at end of file diff --git a/Examples/FactoryExample/infrastructure/main.bicep b/Examples/FactoryExample/infrastructure/main.bicep new file mode 100644 index 0000000..c26e289 --- /dev/null +++ b/Examples/FactoryExample/infrastructure/main.bicep @@ -0,0 +1,42 @@ +// Main template; to deploy use the following: +// az login +// az account set --subscription +// az deployment sub create -l australiaeast -f infrastructure/main.bicep + +targetScope = 'subscription' + +param appName string = 'codefirsttwins' +param environment string = 'demo' +param orgId string = '0x${substring(subscription().subscriptionId, 0, 4)}' + +var tags = { + ApplicationName: appName + WorkloadName: 'codefirsttwins' + DataClassification: 'Non-business' + Criticality: 'Low' + BusinessUnit: 'Demo' + Env: environment +} +var location = deployment().location +var rgName = 'rg-${appName}-${environment}-001' + +resource rgDemoDeployment 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: rgName + location: location + tags: tags + properties: {} +} + +module demoDeployment './demoDeployment-module.bicep' = { + name: 'demoDeployment' + scope: rgDemoDeployment + params: { + appName: appName + orgId: orgId + environment: environment + tags: tags + } + dependsOn: [ + rgDemoDeployment + ] +} \ No newline at end of file diff --git a/Examples/FactoryExample/infrastructure/rg-codefirsttwins-demo-001.bicep b/Examples/FactoryExample/infrastructure/rg-codefirsttwins-demo-001.bicep deleted file mode 100644 index 1531a08..0000000 --- a/Examples/FactoryExample/infrastructure/rg-codefirsttwins-demo-001.bicep +++ /dev/null @@ -1,97 +0,0 @@ -@secure() -param IotHubs_iot_codefirsttwins_0xacc5_demo_connectionString string - -@secure() -param IotHubs_iot_codefirsttwins_0xacc5_demo_containerName string -param IotHubs_iot_codefirsttwins_0xacc5_demo_name string -param digitalTwinsInstances_dt_codefirsttwins_0xacc5_demo_name string - -resource IotHubs_iot_codefirsttwins_0xacc5_demo_name_resource 'Microsoft.Devices/IotHubs@2021-07-01' = { - name: IotHubs_iot_codefirsttwins_0xacc5_demo_name - location: 'australiaeast' - tags: { - ApplicationName: 'codefirsttwins' - WorkloadName: 'codefirsttwins' - DataClassification: 'Non-business' - Criticality: 'Low' - BusinessUnit: 'Demo' - Env: 'demo' - } - sku: { - name: 'S1' - tier: 'Standard' - capacity: 1 - } - identity: { - type: 'None' - } - properties: { - ipFilterRules: [] - eventHubEndpoints: { - events: { - retentionTimeInDays: 1 - partitionCount: 4 - } - } - routing: { - endpoints: { - serviceBusQueues: [] - serviceBusTopics: [] - eventHubs: [] - storageContainers: [] - } - routes: [] - fallbackRoute: { - name: '$fallback' - source: 'DeviceMessages' - condition: 'true' - endpointNames: [ - 'events' - ] - isEnabled: true - } - } - storageEndpoints: { - '$default': { - sasTtlAsIso8601: 'PT1H' - connectionString: IotHubs_iot_codefirsttwins_0xacc5_demo_connectionString - containerName: IotHubs_iot_codefirsttwins_0xacc5_demo_containerName - } - } - messagingEndpoints: { - fileNotifications: { - lockDurationAsIso8601: 'PT1M' - ttlAsIso8601: 'PT1H' - maxDeliveryCount: 10 - } - } - enableFileUploadNotifications: false - cloudToDevice: { - maxDeliveryCount: 10 - defaultTtlAsIso8601: 'PT1H' - feedback: { - lockDurationAsIso8601: 'PT1M' - ttlAsIso8601: 'PT1H' - maxDeliveryCount: 10 - } - } - features: 'None' - } -} - -resource digitalTwinsInstances_dt_codefirsttwins_0xacc5_demo_name_resource 'Microsoft.DigitalTwins/digitalTwinsInstances@2020-12-01' = { - name: digitalTwinsInstances_dt_codefirsttwins_0xacc5_demo_name - location: 'australiaeast' - tags: { - ApplicationName: 'codefirsttwins' - WorkloadName: 'codefirsttwins' - DataClassification: 'Non-business' - Criticality: 'Low' - BusinessUnit: 'Demo' - Env: 'demo' - } - properties: { - privateEndpointConnections: [] - publicNetworkAccess: 'Enabled' - } -} \ No newline at end of file From ae96c2bbded1558bc6419f27880ec600c5d93dee Mon Sep 17 00:00:00 2001 From: Sly Gryphon Date: Thu, 2 Dec 2021 07:14:35 +1000 Subject: [PATCH 15/33] Update powershell deployment --- Examples/FactoryExample/deploy-infrastructure.ps1 | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/Examples/FactoryExample/deploy-infrastructure.ps1 b/Examples/FactoryExample/deploy-infrastructure.ps1 index 17708c0..1e39d0c 100644 --- a/Examples/FactoryExample/deploy-infrastructure.ps1 +++ b/Examples/FactoryExample/deploy-infrastructure.ps1 @@ -1,7 +1,6 @@ #!/usr/bin/env pwsh [CmdletBinding()] param ( - [string]$SubscriptionId = $null, [string]$AppName = 'codefirsttwins', [string]$Environment = 'demo', [string]$Location = 'australiaeast' @@ -17,7 +16,9 @@ param ( # Install-Module -Name Az.DigitalTwins -Scope CurrentUser -Force # Register-AzResourceProvider -ProviderNamespace Microsoft.DigitalTwins # -# You also need to authenticate with: Connect-AzAccount +# You also need to authenticate and set subscription you are using: +# Connect-AzAccount +# Set-AzContext -SubscriptionId $SubscriptionId # # To see messages, set verbose preference before running: # $VerbosePreference = 'Continue' @@ -25,13 +26,8 @@ param ( $ErrorActionPreference="Stop" -if ($SubscriptionId) { - Write-Verbose "Setting context to subscription ID $SubscriptionId" - Set-AzContext -SubscriptionId $SubscriptionId -} else { - $SubscriptionId = (Get-AzContext).Subscription.Id - Write-Verbose "Using existing context subscription ID $SubscriptionId" -} +$SubscriptionId = (Get-AzContext).Subscription.Id +Write-Verbose "Using context subscription ID $SubscriptionId" # Following standard naming conventions from Azure Cloud Adoption Framework # https://docs.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/resource-naming From b8199ff23224d5028a4b09ce9d0436d41b8bfb91 Mon Sep 17 00:00:00 2001 From: Sly Gryphon Date: Thu, 2 Dec 2021 07:33:52 +1000 Subject: [PATCH 16/33] Cleanup remove --- Examples/FactoryExample/remove-infrastructure.ps1 | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/Examples/FactoryExample/remove-infrastructure.ps1 b/Examples/FactoryExample/remove-infrastructure.ps1 index f440f58..5cdbeed 100644 --- a/Examples/FactoryExample/remove-infrastructure.ps1 +++ b/Examples/FactoryExample/remove-infrastructure.ps1 @@ -19,13 +19,8 @@ param ( $ErrorActionPreference="Stop" -if (-not $SubscriptionId) { - Write-Verbose "Using default subscription ID" - $SubscriptionId = (ConvertFrom-Json "$(az account show)").id -} - -$AppName = 'codefirsttwins' -$Environment = 'demo' +$SubscriptionId = (Get-AzContext).Subscription.Id +Write-Verbose "Removing from context subscription ID $SubscriptionId" $ResourceGroupName = "rg-$AppName-$Environment-001" From 922c8c4af3388da362a213f28271d05297b051a3 Mon Sep 17 00:00:00 2001 From: Sly Gryphon Date: Tue, 14 Dec 2021 07:24:21 +1000 Subject: [PATCH 17/33] WIP - infrastructure scripts --- .../deploy-infrastructure-azcli.ps1 | 64 -------------- .../FactoryExample/deploy-infrastructure.ps1 | 83 +++++++++++------- .../rg-codefirsttwins-demo-001.json | 85 ------------------- .../0001 - Create resource group.ps1 | 18 ++++ .../infrastructure/0002 - Create IOT hub.ps1 | 22 +++++ .../0003 - Create Digital Twins service.ps1 | 20 +++++ .../infrastructure/9001 - Output settings.ps1 | 18 ++++ .../demoDeployment-module.bicep | 26 ------ .../FactoryExample/infrastructure/main.bicep | 42 --------- 9 files changed, 131 insertions(+), 247 deletions(-) delete mode 100644 Examples/FactoryExample/deploy-infrastructure-azcli.ps1 delete mode 100644 Examples/FactoryExample/infrastructure-arm/rg-codefirsttwins-demo-001.json create mode 100644 Examples/FactoryExample/infrastructure/0001 - Create resource group.ps1 create mode 100644 Examples/FactoryExample/infrastructure/0002 - Create IOT hub.ps1 create mode 100644 Examples/FactoryExample/infrastructure/0003 - Create Digital Twins service.ps1 create mode 100644 Examples/FactoryExample/infrastructure/9001 - Output settings.ps1 delete mode 100644 Examples/FactoryExample/infrastructure/demoDeployment-module.bicep delete mode 100644 Examples/FactoryExample/infrastructure/main.bicep diff --git a/Examples/FactoryExample/deploy-infrastructure-azcli.ps1 b/Examples/FactoryExample/deploy-infrastructure-azcli.ps1 deleted file mode 100644 index e9c7794..0000000 --- a/Examples/FactoryExample/deploy-infrastructure-azcli.ps1 +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env pwsh -[CmdletBinding()] -param ( - [string]$SubscriptionId = $null, - [string]$AppName = 'codefirsttwins', - [string]$Environment = 'demo', - [string]$Location = 'australiaeast' -) - -# Pre-requisites: -# -# Running these scripts requires the following to be installed: -# * PowerShell, https://github.com/PowerShell/PowerShell -# * Azure CLI, https://docs.microsoft.com/en-us/cli/azure -# * IoT Extension for Azure CLI: -# az extension add --upgrade --name azure-iot -# az provider register --namespace 'Microsoft.DigitalTwins' -# -# You also need to run `az login` to authenticate -# -# To see messages, set verbose preference before running: -# $VerbosePreference = 'Continue' -# ./deploy-infrastructure.ps1 - -$ErrorActionPreference="Stop" - -if (-not $SubscriptionId) { - Write-Verbose "Using default subscription ID" - $SubscriptionId = (ConvertFrom-Json "$(az account show)").id -} - -# Following standard naming conventions from Azure Cloud Adoption Framework -# https://docs.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/resource-naming - -# Include an subscription or organisation identifier (after app name) in global names to make them unique -$OrgId = "0x$($SubscriptionId.Substring(0,4))" - -$ResourceGroupName = "rg-$AppName-$Environment-001" -$DigitalTwinsName = "dt-$AppName-$OrgId-$Environment" -$IotHubName = "iot-$AppName-$OrgId-$Environment" - -# Following standard tagging conventions from Azure Cloud Adoption Framework -# https://docs.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/resource-tagging - -$Tag = @{ WorkloadName = 'codefirsttwins'; DataClassification = 'Non-business'; Criticality = 'Low'; - BusinessUnit = 'Demo'; ApplicationName = $AppName; Env = $Environment } - -# Create - -az group create -g $ResourceGroupName -l $Location --subscription $SubscriptionId ` - --tags "WorkloadName=$($Tag.WorkloadName)" "DataClassification=$($Tag.DataClassification)" "Criticality=$($Tag.Criticality)" ` - "BusinessUnit=$($Tag.BusinessUnit)" "ApplicationName=$($Tag.ApplicationName)" "Env=$($Tag.Env)" - -az dt create --dt-name $DigitalTwinsName --resource-group $ResourceGroupName --location $Location ` - --tags "WorkloadName=$($Tag.WorkloadName)" "DataClassification=$($Tag.DataClassification)" "Criticality=$($Tag.Criticality)" ` - "BusinessUnit=$($Tag.BusinessUnit)" "ApplicationName=$($Tag.ApplicationName)" "Env=$($Tag.Env)" - -az iot hub create --name $IotHubName --resource-group $ResourceGroupName --sku S1 ` - --tags "WorkloadName=$($Tag.WorkloadName)" "DataClassification=$($Tag.DataClassification)" "Criticality=$($Tag.Criticality)" ` - "BusinessUnit=$($Tag.BusinessUnit)" "ApplicationName=$($Tag.ApplicationName)" "Env=$($Tag.Env)" - -# Output - -az dt show --dt-name $DigitalTwinsName diff --git a/Examples/FactoryExample/deploy-infrastructure.ps1 b/Examples/FactoryExample/deploy-infrastructure.ps1 index 1e39d0c..5f343db 100644 --- a/Examples/FactoryExample/deploy-infrastructure.ps1 +++ b/Examples/FactoryExample/deploy-infrastructure.ps1 @@ -1,11 +1,56 @@ #!/usr/bin/env pwsh + +<# +.SYNOPSIS + Deploy the Azure infrastructure for the project. + +.NOTES + + Running these scripts requires the following to be installed: + * PowerShell, https://github.com/PowerShell/PowerShell + * Azure PowerShell module, https://docs.microsoft.com/en-us/powershell/azure/install-az-ps + * Azure Digital Twins module (preview installed separately) + + You also need to connect to Azure (log in), and set the desired subscripition context. + + Follow standard naming conventions from Azure Cloud Adoption Framework, + with an additional organisation or subscription identifier (after app name) in global names + to make them unique. + https://docs.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/resource-naming + + Follow standard tagging conventions from Azure Cloud Adoption Framework. + https://docs.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/resource-tagging + +.EXAMPLE + + Install-Module -Name Az -Scope CurrentUser -Force + Install-Module -Name Az.DigitalTwins -Scope CurrentUser -Force + Register-AzResourceProvider -ProviderNamespace Microsoft.DigitalTwins + Connect-AzAccount + Set-AzContext -SubscriptionId $SubscriptionId + $VerbosePreference = 'Continue' + ./deploy-infrastructure.ps1 +#> [CmdletBinding()] param ( - [string]$AppName = 'codefirsttwins', - [string]$Environment = 'demo', - [string]$Location = 'australiaeast' + ## Number of initial scripts to skip (if they have already been run) + [int]$Skip = 0, + ## Deployment environment, e.g. Prod, Dev, QA, Stage, Test. + [string]$Environment = $ENV:DEPLOY_ENVIRONMENT ?? 'Dev', + ## The Azure region where the resource is deployed. + [string]$Location = $ENV:DEPLOY_LOCATION ?? 'australiaeast', + ## Identifier for the organisation (or subscription) to make global names unique. + [string]$OrgId = $ENV:DEPLOY_ORGID ?? "0x$((Get-AzContext).Subscription.Id.Substring(0,4))" ) +# Following standard naming conventions from Azure Cloud Adoption Framework +# https://docs.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/resource-naming +# With an additional organisation or subscription identifier (after app name) in global names to make them unique + +# Following standard tagging conventions from Azure Cloud Adoption Framework +# https://docs.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/resource-tagging + + # Pre-requisites: # # Running these scripts requires the following to be installed: @@ -29,32 +74,10 @@ $ErrorActionPreference="Stop" $SubscriptionId = (Get-AzContext).Subscription.Id Write-Verbose "Using context subscription ID $SubscriptionId" -# Following standard naming conventions from Azure Cloud Adoption Framework -# https://docs.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/resource-naming - -# Include an subscription or organisation identifier (after app name) in global names to make them unique -$OrgId = "0x$($SubscriptionId.Substring(0,4))" - -$ResourceGroupName = "rg-$AppName-$Environment-001" -$DigitalTwinsName = "dt-$AppName-$OrgId-$Environment" -$IotHubName = "iot-$AppName-$OrgId-$Environment" - -# Following standard tagging conventions from Azure Cloud Adoption Framework -# https://docs.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/resource-tagging - -$Tag = @{ WorkloadName = 'codefirsttwins'; DataClassification = 'Non-business'; Criticality = 'Low'; - BusinessUnit = 'Demo'; ApplicationName = $AppName; Env = $Environment } - -# Create - -New-AzResourceGroup -Name $ResourceGroupName -Location $Location -Tag $Tag -Force - -New-AzDigitalTwinsInstance -ResourceGroupName $ResourceGroupName -ResourceName $DigitalTwinsName -Location $Location -Tag $Tag - -New-AzIotHub -ResourceGroupName $ResourceGroupName -Name $IotHubName -SkuName S1 -Units 1 -Location $Location -Tag $Tag - -# Output +$scriptItems = Get-ChildItem "$PSScriptRoot/infrastructure" -Filter '*.ps1' ` + | Sort-Object -Property Name ` + | Select-Object -Skip $Skip -(Get-AzDigitalTwinsInstance -ResourceGroupName $ResourceGroupName -ResourceName $DigitalTwinsName).HostName -(Get-AzIotHub $ResourceGroupName).Properties.HostName +$scriptItems | ForEach-Object { Write-Verbose "Running $($_.Name)"; & $_.FullName; } +Write-Verbose "Deployment Complete" diff --git a/Examples/FactoryExample/infrastructure-arm/rg-codefirsttwins-demo-001.json b/Examples/FactoryExample/infrastructure-arm/rg-codefirsttwins-demo-001.json deleted file mode 100644 index cf867f0..0000000 --- a/Examples/FactoryExample/infrastructure-arm/rg-codefirsttwins-demo-001.json +++ /dev/null @@ -1,85 +0,0 @@ -// Connect-AzAccount -// Set-AzContext -Subscription -// New-AzDeployment -Location 'australiaeast' -TemplateFile 'infrastructure-arm/rg-codefirsttwins-demo-001.json' -{ - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "appName": { - "type": "String", - "defaultValue": "codefirsttwins" - }, - "environment": { - "type": "String", - "defaultValue": "demo" - }, - "location": { - "type": "String", - "defaultValue": "[deployment().location]" - }, - "orgId": { - "type": "String", - "defaultValue": "[concat('0x',substring(subscription().subscriptionId, 0, 4))]" - } - }, - "variables": { - "tags": { - "ApplicationName": "[parameters('appName')]", - "WorkloadName": "codefirsttwins", - "DataClassification": "Non-business", - "Criticality": "Low", - "BusinessUnit": "Demo", - "Env": "[parameters('environment')]" - }, - "rgName": "[concat('rg-',parameters('appName'),'-',parameters('environment'),'-001')]" - }, - "resources": [ - { - "type": "Microsoft.Resources/resourceGroups", - "apiVersion": "2021-04-01", - "name": "[variables('rgName')]", - "location": "[parameters('location')]", - "tags": "[variables('tags')]", - "properties": {} - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2021-04-01", - "name": "demoDeployment", - "resourceGroup": "[variables('rgName')]", - "dependsOn": [ - "[resourceId('Microsoft.Resources/resourceGroups/', variables('rgName'))]" - ], - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": {}, - "variables": {}, - "resources": [ - { - "type": "Microsoft.Devices/IotHubs", - "apiVersion": "2021-07-01", - "name": "[concat('iot-',parameters('appName'),'-',parameters('orgId'),'-',parameters('environment'))]", - "location": "[parameters('location')]", - "tags": "[variables('tags')]", - "sku": { - "name": "S1", - "tier": "Standard", - "capacity": 1 - } - }, - { - "type": "Microsoft.DigitalTwins/digitalTwinsInstances", - "apiVersion": "2020-12-01", - "name": "[concat('dt-',parameters('appName'),'-',parameters('orgId'),'-',parameters('environment'))]", - "location": "[parameters('location')]", - "tags": "[variables('tags')]" - } - ] - } - } - } - ] -} \ No newline at end of file diff --git a/Examples/FactoryExample/infrastructure/0001 - Create resource group.ps1 b/Examples/FactoryExample/infrastructure/0001 - Create resource group.ps1 new file mode 100644 index 0000000..177a111 --- /dev/null +++ b/Examples/FactoryExample/infrastructure/0001 - Create resource group.ps1 @@ -0,0 +1,18 @@ +#!/usr/bin/env pwsh + +[CmdletBinding()] +param ( + [string]$Environment, + [string]$Location, + [string]$OrgId +) + +$appName = 'codefirsttwins' + +$rgName = "rg-$appName-$Environment-001".ToLowerInvariant() +$tags = @{ WorkloadName = 'codefirsttwins'; DataClassification = 'Non-business'; Criticality = 'Low'; ` + BusinessUnit = 'Demo'; ApplicationName = $appName; Env = $Environment } + +Write-Verbose "Creating resource group $rgName in location $Location" + +New-AzResourceGroup -Name $rgName -Location $Location -Tag $tags -Force diff --git a/Examples/FactoryExample/infrastructure/0002 - Create IOT hub.ps1 b/Examples/FactoryExample/infrastructure/0002 - Create IOT hub.ps1 new file mode 100644 index 0000000..64b8e29 --- /dev/null +++ b/Examples/FactoryExample/infrastructure/0002 - Create IOT hub.ps1 @@ -0,0 +1,22 @@ +#!/usr/bin/env pwsh + +[CmdletBinding()] +param ( + [string]$Environment, + [string]$Location, + [string]$OrgId +) + +$appName = 'codefirsttwins' +$iotSku = 'S1' +$iotUnits = 1 + +$rgName = "rg-$appName-$Environment-001".ToLowerInvariant() +$rg = Get-AzResourceGroup -Name $rgName + +$iotName = "iot-$appName-$OrgId-$Environment".ToLowerInvariant() + +Write-Verbose "Creating IOT hub $iotName in resource group $rgName" + +New-AzIotHub -Name $iotName -SkuName $iotSku -Units $iotUnits ` + -ResourceGroupName $rgName -Location $rg.Location -Tag $rg.Tags diff --git a/Examples/FactoryExample/infrastructure/0003 - Create Digital Twins service.ps1 b/Examples/FactoryExample/infrastructure/0003 - Create Digital Twins service.ps1 new file mode 100644 index 0000000..c7e57d8 --- /dev/null +++ b/Examples/FactoryExample/infrastructure/0003 - Create Digital Twins service.ps1 @@ -0,0 +1,20 @@ +#!/usr/bin/env pwsh + +[CmdletBinding()] +param ( + [string]$Environment, + [string]$Location, + [string]$OrgId +) + +$appName = 'codefirsttwins' + +$rgName = "rg-$appName-$Environment-001".ToLowerInvariant() +$rg = Get-AzResourceGroup -Name $rgName + +$dtName = "dt-$appName-$OrgId-$Environment".ToLowerInvariant() + +Write-Verbose "Creating digital twins service $dtName in resource group $rgName" + +New-AzDigitalTwinsInstance -ResourceName $dtName ` + -ResourceGroupName $rgName -Location $rg.Location -Tag $rg.Tags diff --git a/Examples/FactoryExample/infrastructure/9001 - Output settings.ps1 b/Examples/FactoryExample/infrastructure/9001 - Output settings.ps1 new file mode 100644 index 0000000..e694aae --- /dev/null +++ b/Examples/FactoryExample/infrastructure/9001 - Output settings.ps1 @@ -0,0 +1,18 @@ +#!/usr/bin/env pwsh + +[CmdletBinding()] +param ( + [string]$Environment, + [string]$Location, + [string]$OrgId +) + +$appName = 'codefirsttwins' +$rgName = "rg-$appName-$Environment-001".ToLowerInvariant() +$dtName = "dt-$appName-$OrgId-$Environment".ToLowerInvariant() + +Write-Verbose 'Digital Twins host name:' +(Get-AzDigitalTwinsInstance -ResourceGroupName $rgName -ResourceName $dtName).HostName + +Write-Verbose 'IOT Hub host name:' +(Get-AzIotHub $rgName).Properties.HostName diff --git a/Examples/FactoryExample/infrastructure/demoDeployment-module.bicep b/Examples/FactoryExample/infrastructure/demoDeployment-module.bicep deleted file mode 100644 index cd57707..0000000 --- a/Examples/FactoryExample/infrastructure/demoDeployment-module.bicep +++ /dev/null @@ -1,26 +0,0 @@ -// Module for deploying resource group items (default target scope) - -param appName string -param orgId string -param environment string -param tags object - -var location = resourceGroup().location -var iotHubName = 'iot-${appName}-${orgId}-${environment}' -var digitalTwinsName = 'dt-${appName}-${orgId}-${environment}' - -resource iot_appName_orgId_environment 'Microsoft.Devices/IotHubs@2021-07-01' = { - name: iotHubName - location: location - tags: tags - sku: { - name: 'S1' - capacity: 1 - } -} - -resource dt_appName_orgId_environment 'Microsoft.DigitalTwins/digitalTwinsInstances@2020-12-01' = { - name: digitalTwinsName - location: location - tags: tags -} \ No newline at end of file diff --git a/Examples/FactoryExample/infrastructure/main.bicep b/Examples/FactoryExample/infrastructure/main.bicep deleted file mode 100644 index c26e289..0000000 --- a/Examples/FactoryExample/infrastructure/main.bicep +++ /dev/null @@ -1,42 +0,0 @@ -// Main template; to deploy use the following: -// az login -// az account set --subscription -// az deployment sub create -l australiaeast -f infrastructure/main.bicep - -targetScope = 'subscription' - -param appName string = 'codefirsttwins' -param environment string = 'demo' -param orgId string = '0x${substring(subscription().subscriptionId, 0, 4)}' - -var tags = { - ApplicationName: appName - WorkloadName: 'codefirsttwins' - DataClassification: 'Non-business' - Criticality: 'Low' - BusinessUnit: 'Demo' - Env: environment -} -var location = deployment().location -var rgName = 'rg-${appName}-${environment}-001' - -resource rgDemoDeployment 'Microsoft.Resources/resourceGroups@2021-04-01' = { - name: rgName - location: location - tags: tags - properties: {} -} - -module demoDeployment './demoDeployment-module.bicep' = { - name: 'demoDeployment' - scope: rgDemoDeployment - params: { - appName: appName - orgId: orgId - environment: environment - tags: tags - } - dependsOn: [ - rgDemoDeployment - ] -} \ No newline at end of file From ef1fcb5eba3597508bb2028a9422b314b94dd574 Mon Sep 17 00:00:00 2001 From: Sly Gryphon Date: Tue, 14 Dec 2021 23:15:07 +1000 Subject: [PATCH 18/33] Update infrastructure scripts & check they run --- .../FactoryExample/deploy-infrastructure.ps1 | 5 ++- .../FactoryExample/remove-infrastructure.ps1 | 31 +++++++++---------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Examples/FactoryExample/deploy-infrastructure.ps1 b/Examples/FactoryExample/deploy-infrastructure.ps1 index 5f343db..9796c78 100644 --- a/Examples/FactoryExample/deploy-infrastructure.ps1 +++ b/Examples/FactoryExample/deploy-infrastructure.ps1 @@ -78,6 +78,9 @@ $scriptItems = Get-ChildItem "$PSScriptRoot/infrastructure" -Filter '*.ps1' ` | Sort-Object -Property Name ` | Select-Object -Skip $Skip -$scriptItems | ForEach-Object { Write-Verbose "Running $($_.Name)"; & $_.FullName; } +$scriptItems | ForEach-Object { + Write-Verbose "Running $($_.Name)" + & $_.FullName -Environment $Environment -Location $Location -OrgId $OrgId +} Write-Verbose "Deployment Complete" diff --git a/Examples/FactoryExample/remove-infrastructure.ps1 b/Examples/FactoryExample/remove-infrastructure.ps1 index 5cdbeed..594af16 100644 --- a/Examples/FactoryExample/remove-infrastructure.ps1 +++ b/Examples/FactoryExample/remove-infrastructure.ps1 @@ -1,27 +1,24 @@ +#!/usr/bin/env pwsh + [CmdletBinding()] param ( - [string]$SubscriptionId = $null, - [string]$AppName = 'codefirsttwins', - [string]$Environment = 'demo' + ## Number of initial scripts to skip (if they have already been run) + [int]$Skip = 0, + ## Deployment environment, e.g. Prod, Dev, QA, Stage, Test. + [string]$Environment = $ENV:DEPLOY_ENVIRONMENT ?? 'Dev', + ## The Azure region where the resource is deployed. + [string]$Location = $ENV:DEPLOY_LOCATION ?? 'australiaeast', + ## Identifier for the organisation (or subscription) to make global names unique. + [string]$OrgId = $ENV:DEPLOY_ORGID ?? "0x$((Get-AzContext).Subscription.Id.Substring(0,4))" ) -# Pre-requisites: -# -# Running these scripts requires the following to be installed: -# * PowerShell, https://github.com/PowerShell/PowerShell -# * Azure CLI, https://docs.microsoft.com/en-us/cli/azure -# -# You also need to run `az login` to authenticate -# -# To see messages, set verbose preference before running: -# $VerbosePreference = 'Continue' -# ./deploy-infrastructure.ps1 - $ErrorActionPreference="Stop" $SubscriptionId = (Get-AzContext).Subscription.Id Write-Verbose "Removing from context subscription ID $SubscriptionId" -$ResourceGroupName = "rg-$AppName-$Environment-001" +$appName = 'codefirsttwins' + +$rgName = "rg-$appName-$Environment-001".ToLowerInvariant() -Remove-AzResourceGroup -Name $ResourceGroupName +Remove-AzResourceGroup -Name $rgName From aadd9a09c9511aefe1a7f8f7db2006fff2c3c91e Mon Sep 17 00:00:00 2001 From: Sly Gryphon Date: Tue, 14 Dec 2021 23:40:55 +1000 Subject: [PATCH 19/33] Update sample objects for new library capabilities (semantic types, etc) --- .../FactoryExample/Devices/ProductionStep.cs | 9 ++++++--- .../Devices/ProductionStepGrinding.cs | 16 ++++++---------- Examples/FactoryExample/Models/Factory.cs | 15 ++++++++++----- Examples/FactoryExample/Models/FactoryFloor.cs | 15 +++++++++------ Examples/FactoryExample/Models/ProductionLine.cs | 13 +++++++------ 5 files changed, 38 insertions(+), 30 deletions(-) diff --git a/Examples/FactoryExample/Devices/ProductionStep.cs b/Examples/FactoryExample/Devices/ProductionStep.cs index 9522fee..ba99cba 100644 --- a/Examples/FactoryExample/Devices/ProductionStep.cs +++ b/Examples/FactoryExample/Devices/ProductionStep.cs @@ -7,16 +7,19 @@ 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 DateTimeOffset? StartTime { get; set; } [TwinProperty] public string? StepId { get; set; } - //[TwinRelationship(DisplayName = "Step Link")] - [TwinRelationship(MaxMultiplicity = 500)] + [TwinRelationship(DisplayName = "Step Link")] public ProductionStep? StepLink { get; set; } [TwinProperty] public string? StepName { get; set; } diff --git a/Examples/FactoryExample/Devices/ProductionStepGrinding.cs b/Examples/FactoryExample/Devices/ProductionStepGrinding.cs index 0e82b8e..22a152c 100644 --- a/Examples/FactoryExample/Devices/ProductionStepGrinding.cs +++ b/Examples/FactoryExample/Devices/ProductionStepGrinding.cs @@ -1,4 +1,5 @@ using Telstra.Twins.Attributes; +using Telstra.Twins.Semantics; namespace FactoryExample.Devices { @@ -6,24 +7,19 @@ namespace FactoryExample.Devices ExtendsModelId = "dtmi:factoryexample:devices:productionstep;1")] public class ProductionStepGrinding : ProductionStep { - //[TwinTelemetry(Unit = "degreeCelsius", SemanticType = "Temperature")] - [TwinTelemetry] + [TwinProperty(SemanticType = SemanticType.Temperature, Unit = TemperatureUnit.DegreeCelsius, Writable = true)] public double? ChassisTemperature { get; set; } - //[TwinTelemetry(Unit = "newton", SemanticType = "Force")] - [TwinTelemetry] + [TwinProperty(SemanticType = SemanticType.Force, Unit = ForceUnit.Newton)] public double? Force { get; set; } - //[TwinTelemetry(Unit = "minute", SemanticType = "TimeSpan")] - [TwinTelemetry] + [TwinProperty(SemanticType = SemanticType.TimeSpan, Unit = TimeUnit.Minute)] public int? GrindingTime { get; set; } - //[TwinTelemetry(Unit = "kilowatt", SemanticType = "Power")] - [TwinTelemetry] + [TwinProperty(SemanticType = SemanticType.Power, Unit = PowerUnit.Kilowatt)] public double? PowerUsage { get; set; } - //[TwinTelemetry(Unit = "hertz", SemanticType = "Frequency")] - [TwinTelemetry] + [TwinProperty(SemanticType = SemanticType.Frequency, Unit = FrequencyUnit.Hertz)] public double? Vibration { get; set; } } } diff --git a/Examples/FactoryExample/Models/Factory.cs b/Examples/FactoryExample/Models/Factory.cs index bd2a905..2bd8984 100644 --- a/Examples/FactoryExample/Models/Factory.cs +++ b/Examples/FactoryExample/Models/Factory.cs @@ -13,16 +13,21 @@ public class Factory : TwinBase [TwinProperty] public string? FactoryId { get; set; } - [TwinProperty] public string? FactoryName { get; set; } + [TwinProperty(Writable = true)] public string? FactoryName { get; set; } - //[TwinRelationship(DisplayName = "Has Floors")] - [TwinRelationship(MaxMultiplicity = 500)] + [TwinRelationship(DisplayName = "Has Floors")] public IList Floors { get; } = new List(); [TwinProperty] public GeoCord? GeoLocation { get; set; } - //[TwinProperty] public DateTimeOffset LastSupplyDate { get; set; } + [TwinProperty] public DateTimeOffset LastSupplyDate { get; set; } + + // ServesRetailer + // SuppliedBy + // TransportationBy + + [TwinProperty(Writable = true)] public string? Tags { get; set; } - [TwinProperty] public string? ZipCode { get; set; } + [TwinProperty(Writable = true)] public string? ZipCode { get; set; } } } diff --git a/Examples/FactoryExample/Models/FactoryFloor.cs b/Examples/FactoryExample/Models/FactoryFloor.cs index 2deffa9..e0a850e 100644 --- a/Examples/FactoryExample/Models/FactoryFloor.cs +++ b/Examples/FactoryExample/Models/FactoryFloor.cs @@ -1,6 +1,8 @@ using System.Collections.Generic; +using MediatR; using Telstra.Twins; using Telstra.Twins.Attributes; +using Telstra.Twins.Semantics; namespace FactoryExample.Models { @@ -9,16 +11,17 @@ public class FactoryFloor : TwinBase { [TwinProperty] public double? ComfortIndex { get; set; } - [TwinProperty] public string? FloorId { get; set; } + [TwinProperty(Writable = true)] public string? FloorId { get; set; } - [TwinProperty] public string? FloorName { get; set; } + // FloorHasRooms + // FloorHasZones + + [TwinProperty(Writable = true)] public string? FloorName { get; set; } - //[TwinRelationship(DisplayName = "Runs Production Lines")] - [TwinRelationship(MaxMultiplicity = 500)] + [TwinRelationship(DisplayName = "Runs Production Lines")] public IList RunsLines { get; } = new List(); - //[TwinTelemetry(Unit = "degreeCelsius", SemanticType = "Temperature")] - [TwinTelemetry] + [TwinProperty(SemanticType = SemanticType.Temperature, Unit = TemperatureUnit.DegreeCelsius, Writable = true)] public double? Temperature { get; set; } } } diff --git a/Examples/FactoryExample/Models/ProductionLine.cs b/Examples/FactoryExample/Models/ProductionLine.cs index 7eaef96..c6a94c8 100644 --- a/Examples/FactoryExample/Models/ProductionLine.cs +++ b/Examples/FactoryExample/Models/ProductionLine.cs @@ -8,18 +8,19 @@ namespace FactoryExample.Models [DigitalTwin(Version = 1, DisplayName = "Factory Production Line - Interface Model")] public class ProductionLine : TwinBase { - [TwinProperty] public string? CurrentProductId { get; set; } + // ContainsEquipment + + [TwinProperty(Writable = true)] public string? CurrentProductId { get; set; } - [TwinProperty] public string? LineId { get; set; } + [TwinProperty(Writable = true)] public string? LineId { get; set; } - [TwinProperty] public string? LineName { get; set; } + [TwinProperty(Writable = true)] public string? LineName { get; set; } //[TwinProperty] public ProductionLineStatus LineOperationStatus { get; set; } - [TwinProperty] public int? ProductBatchNumber { get; set; } + [TwinProperty(Writable = true)] public int? ProductBatchNumber { get; set; } - //[TwinRelationship(DisplayName = "Runs Steps")] - [TwinRelationship(MaxMultiplicity = 500)] + [TwinRelationship(DisplayName = "Runs Steps")] public IList RunsSteps { get; } = new List(); } } From 58854af513c9dd73994f6104607190397258fd40 Mon Sep 17 00:00:00 2001 From: Sly Gryphon Date: Wed, 15 Dec 2021 07:04:27 +1000 Subject: [PATCH 20/33] Convert example back to .NET 3.1 LTS --- Examples/FactoryExample/FactoryExample.csproj | 3 +- Examples/FactoryExample/Program.cs | 294 ++++++++++-------- 2 files changed, 160 insertions(+), 137 deletions(-) diff --git a/Examples/FactoryExample/FactoryExample.csproj b/Examples/FactoryExample/FactoryExample.csproj index 80d533b..fd895e1 100644 --- a/Examples/FactoryExample/FactoryExample.csproj +++ b/Examples/FactoryExample/FactoryExample.csproj @@ -2,8 +2,7 @@ Exe - net6.0 - enable + netcoreapp3.1 enable diff --git a/Examples/FactoryExample/Program.cs b/Examples/FactoryExample/Program.cs index 23bc523..46716c0 100644 --- a/Examples/FactoryExample/Program.cs +++ b/Examples/FactoryExample/Program.cs @@ -5,161 +5,185 @@ using FactoryExample.Devices; using FactoryExample.Models; using FactoryExample.Schema; -using Microsoft.AspNetCore.Mvc.ApplicationModels; -using Microsoft.Azure.DigitalTwins.Parser; using Microsoft.Extensions.Configuration; using Telstra.Twins.Core; using Telstra.Twins.Services; -Console.WriteLine("Digital Twin Code First Factory Example"); - -var configuration = new ConfigurationBuilder() - .AddJsonFile("appsettings.json", true) - .AddEnvironmentVariables() - .AddCommandLine(args) - .Build(); - -var show = configuration.GetValue("show"); -if (!string.IsNullOrWhiteSpace(show)) +namespace FactoryExample { - switch (show.ToLowerInvariant()) + class Program { - case "model": - var modelTypes = new[] - { - typeof(Factory), typeof(FactoryFloor), typeof(ProductionLine), typeof(ProductionStep), - typeof(ProductionStepGrinding) - }; - ShowModels(modelTypes); - return; - case "example": - ShowExamples(); - return; - } -} + static async Task Main(string[] args) + { + Console.WriteLine("Digital Twin Code First Factory Example"); -var create = configuration.GetValue("create"); -if (!string.IsNullOrWhiteSpace(create)) -{ - switch (create.ToLowerInvariant()) - { - case "model": - var modelTypes = new[] + var configuration = new ConfigurationBuilder() + .AddJsonFile("appsettings.json", true) + .AddEnvironmentVariables() + .AddCommandLine(args) + .Build(); + + var show = configuration.GetValue("show"); + if (!string.IsNullOrWhiteSpace(show)) { - typeof(Factory), typeof(FactoryFloor), typeof(ProductionLine), typeof(ProductionStep), - typeof(ProductionStepGrinding) - }; - await CreateModels(modelTypes); - return; - } -} + switch (show.ToLowerInvariant()) + { + case "model": + var modelTypes = new[] + { + typeof(Factory), typeof(FactoryFloor), typeof(ProductionLine), + typeof(ProductionStep), typeof(ProductionStepGrinding) + }; + ShowModels(modelTypes); + return; + case "example": + ShowExamples(); + return; + } + } + + var check = configuration.GetValue("parse"); + if (!string.IsNullOrWhiteSpace(check)) + { + switch (check.ToLowerInvariant()) + { + case "model": + var modelTypes = new[] + { + typeof(Factory), typeof(FactoryFloor), typeof(ProductionLine), + typeof(ProductionStep), typeof(ProductionStepGrinding) + }; + await ParseModels(modelTypes); + return; + } + } + + var create = configuration.GetValue("create"); + if (!string.IsNullOrWhiteSpace(create)) + { + switch (create.ToLowerInvariant()) + { + case "model": + var modelTypes = new[] + { + typeof(Factory), typeof(FactoryFloor), typeof(ProductionLine), + typeof(ProductionStep), typeof(ProductionStepGrinding) + }; + await ParseModels(modelTypes); + return; + } + } + + ShowHelp(); + } -ShowHelp(); + static async Task ParseModels(Type[] modelTypes) + { + var modelLibrary = new ModelLibrary(); + var serializer = new DigitalTwinSerializer(modelLibrary); -async Task CreateModels(Type[] modelTypes) -{ - var modelLibrary = new ModelLibrary(); - var serializer = new DigitalTwinSerializer(modelLibrary); + var models = modelTypes.Select(x => serializer.SerializeModel(x)); - var models = modelTypes.Select(x => serializer.SerializeModel(x)); + try + { + var parser = new Microsoft.Azure.DigitalTwins.Parser.ModelParser(); + var entityInfos = await parser.ParseAsync(models); + Console.WriteLine($"PARSE SUCCESS:"); + foreach (var kvp in entityInfos) + { + Console.WriteLine( + $"[{kvp.Key}] = {kvp.Value.EntityKind} {kvp.Value.Id} ({kvp.Value.DisplayName.FirstOrDefault().Value})"); + } + } + catch (Microsoft.Azure.DigitalTwins.Parser.ParsingException ex) + { + Console.WriteLine($"PARSE FAILED: {ex.Message}"); + Console.WriteLine($"ERRORS:"); + var count = 0; + foreach (var error in ex.Errors) + { + Console.WriteLine($"{++count}. {error}"); + } + } + catch (RequestFailedException ex) + { + Console.WriteLine($"REQUEST FAILED: {ex.Message}"); + } + } - // Validate - try - { - var parser = new ModelParser(); - var entityInfos = await parser.ParseAsync(models); - Console.WriteLine($"PARSE RESULTS:"); - foreach (var kvp in entityInfos) + static void ShowHelp() { - Console.WriteLine($"[{kvp.Key}] = {kvp.Value.EntityKind} {kvp.Value.Id} ({kvp.Value.DisplayName.FirstOrDefault().Value})"); + Console.WriteLine(" --show model : shows the serialized model"); + Console.WriteLine(" --show example : shows a serialized twin"); + Console.WriteLine(" --parse model : validate the model"); + Console.WriteLine(" --create model : validate and uploads the model"); } - } - catch (ParsingException ex) - { - Console.WriteLine($"PARSE FAILED: {ex.Message}"); - Console.WriteLine($"ERRORS:"); - var count = 0; - foreach (var error in ex.Errors) + + static void ShowModels(Type[] modelTypes) { - Console.WriteLine($"{++count}. {error}"); + var modelLibrary = new ModelLibrary(); + var serializer = new DigitalTwinSerializer(modelLibrary); + + foreach (var modelType in modelTypes) + { + var modelDtdl = serializer.SerializeModel(modelType); + Console.WriteLine(modelDtdl); + Console.WriteLine(); + } } - } - catch (RequestFailedException ex) - { - Console.WriteLine($"REQUEST FAILED: {ex.Message}"); - } -} -void ShowHelp() -{ - Console.WriteLine(" --show model : shows the serialized model"); - Console.WriteLine(" --show example : shows a serialized twin"); - Console.WriteLine(" --create model : validate and uploads the model"); -} + static void ShowExamples() + { + var modelLibrary = new ModelLibrary(); + var serializer = new DigitalTwinSerializer(modelLibrary); -void ShowModels(Type[] modelTypes) -{ - var modelLibrary = new ModelLibrary(); - var serializer = new DigitalTwinSerializer(modelLibrary); + var productionStepGrinding = new ProductionStepGrinding + { + ChassisTemperature = 50, + FinalStep = false, + Force = 8.0, + GrindingTime = 30, + //OperationStatus = ProductionStepStatus.Online, + PowerUsage = 100, + //StartTime = new DateTimeOffset(2021, 11, 17, 19, 57, 0, TimeSpan.FromHours(10)), + StepId = "step1", + StepName = "GrindingStep" + }; - foreach (var modelType in modelTypes) - { - var modelDtdl = serializer.SerializeModel(modelType); - Console.WriteLine(modelDtdl); - Console.WriteLine(); - } -} + var productionLine = new ProductionLine + { + CurrentProductId = "production1", + LineId = "line1", + LineName = "ProductionLine", + //LineOperationStatus = ProductionLineStatus.Online, + ProductBatchNumber = 5 + }; + productionLine.RunsSteps.Add(productionStepGrinding); -void ShowExamples() -{ - var modelLibrary = new ModelLibrary(); - var serializer = new DigitalTwinSerializer(modelLibrary); + var factoryFloor = new FactoryFloor + { + FloorId = "floor1", FloorName = "FactoryFloor", Temperature = 23, ComfortIndex = 0.8 + }; + factoryFloor.RunsLines.Add(productionLine); - var productionStepGrinding = new ProductionStepGrinding - { - ChassisTemperature = 50, - FinalStep = false, - Force = 8.0, - GrindingTime = 30, - //OperationStatus = ProductionStepStatus.Online, - PowerUsage = 100, - //StartTime = new DateTimeOffset(2021, 11, 17, 19, 57, 0, TimeSpan.FromHours(10)), - StepId = "step1", - StepName = "GrindingStep" - }; - - var productionLine = new ProductionLine - { - CurrentProductId = "production1", - LineId = "line1", - LineName = "ProductionLine", - //LineOperationStatus = ProductionLineStatus.Online, - ProductBatchNumber = 5 - }; - productionLine.RunsSteps.Add(productionStepGrinding); - - var factoryFloor = new FactoryFloor - { - FloorId = "floor1", FloorName = "FactoryFloor", Temperature = 23, ComfortIndex = 0.8 - }; - factoryFloor.RunsLines.Add(productionLine); + var factory = new Factory + { + FactoryId = "factory1", + Country = "AU", + ZipCode = "4000", + FactoryName = "Chocolate Factory", + GeoLocation = new GeoCord { Latitude = -27.4705, Longitude = 153.026 }, + LastSupplyDate = new DateTimeOffset(2021, 11, 17, 18, 37, 0, TimeSpan.FromHours(10)) + }; + factory.Floors.Add(factoryFloor); - var factory = new Factory - { - FactoryId = "factory1", - Country = "AU", - ZipCode = "4000", - FactoryName = "Chocolate Factory", - GeoLocation = new GeoCord { Latitude = -27.4705, Longitude = 153.026 }, - //LastSupplyDate = new DateTimeOffset(2021, 11, 17, 18, 37, 0, TimeSpan.FromHours(10)) - }; - factory.Floors.Add(factoryFloor); - - var twin1Dtdl = serializer.SerializeTwin(factory); - Console.WriteLine(twin1Dtdl); - Console.WriteLine(); - - var twin2Dtdl = serializer.SerializeTwin(factory.Floors[0].RunsLines[0].RunsSteps[0]); - Console.WriteLine(twin2Dtdl); - Console.WriteLine(); + var twin1Dtdl = serializer.SerializeTwin(factory); + Console.WriteLine(twin1Dtdl); + Console.WriteLine(); + + var twin2Dtdl = serializer.SerializeTwin(factory.Floors[0].RunsLines[0].RunsSteps[0]); + Console.WriteLine(twin2Dtdl); + Console.WriteLine(); + } + } } From 430211141f0deca0b79182ce918d0c14bbc05420 Mon Sep 17 00:00:00 2001 From: Sly Gryphon Date: Wed, 15 Dec 2021 07:24:16 +1000 Subject: [PATCH 21/33] Reorg example into files --- Examples/FactoryExample/ParseExample.cs | 50 +++++++ Examples/FactoryExample/Program.cs | 144 +++----------------- Examples/FactoryExample/SerializeExample.cs | 84 ++++++++++++ 3 files changed, 151 insertions(+), 127 deletions(-) create mode 100644 Examples/FactoryExample/ParseExample.cs create mode 100644 Examples/FactoryExample/SerializeExample.cs diff --git a/Examples/FactoryExample/ParseExample.cs b/Examples/FactoryExample/ParseExample.cs new file mode 100644 index 0000000..eef9be2 --- /dev/null +++ b/Examples/FactoryExample/ParseExample.cs @@ -0,0 +1,50 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using Azure; +using FactoryExample.Devices; +using FactoryExample.Models; +using FactoryExample.Schema; +using Microsoft.Extensions.Configuration; +using Telstra.Twins.Core; +using Telstra.Twins.Services; + +namespace FactoryExample +{ + public static class ParseExample + { + public static async Task ParseModels() + { + var modelLibrary = new ModelLibrary(); + var serializer = new DigitalTwinSerializer(modelLibrary); + + var models = Program.ModelTypes.Select(x => serializer.SerializeModel(x)); + + try + { + var parser = new Microsoft.Azure.DigitalTwins.Parser.ModelParser(); + var entityInfos = await parser.ParseAsync(models); + Console.WriteLine($"PARSE SUCCESS:"); + foreach (var kvp in entityInfos) + { + Console.WriteLine( + $"[{kvp.Key}] = {kvp.Value.EntityKind} {kvp.Value.Id} ({kvp.Value.DisplayName.FirstOrDefault().Value})"); + } + } + catch (Microsoft.Azure.DigitalTwins.Parser.ParsingException ex) + { + Console.WriteLine($"PARSE FAILED: {ex.Message}"); + Console.WriteLine($"ERRORS:"); + var count = 0; + foreach (var error in ex.Errors) + { + Console.WriteLine($"{++count}. {error}"); + } + } + catch (RequestFailedException ex) + { + Console.WriteLine($"REQUEST FAILED: {ex.Message}"); + } + } + } +} diff --git a/Examples/FactoryExample/Program.cs b/Examples/FactoryExample/Program.cs index 46716c0..a86fdd0 100644 --- a/Examples/FactoryExample/Program.cs +++ b/Examples/FactoryExample/Program.cs @@ -13,6 +13,12 @@ namespace FactoryExample { class Program { + public static Type[] ModelTypes = new[] + { + typeof(Factory), typeof(FactoryFloor), typeof(ProductionLine), + typeof(ProductionStep), typeof(ProductionStepGrinding) + }; + static async Task Main(string[] args) { Console.WriteLine("Digital Twin Code First Factory Example"); @@ -23,21 +29,16 @@ static async Task Main(string[] args) .AddCommandLine(args) .Build(); - var show = configuration.GetValue("show"); + var show = configuration.GetValue("serialize"); if (!string.IsNullOrWhiteSpace(show)) { switch (show.ToLowerInvariant()) { case "model": - var modelTypes = new[] - { - typeof(Factory), typeof(FactoryFloor), typeof(ProductionLine), - typeof(ProductionStep), typeof(ProductionStepGrinding) - }; - ShowModels(modelTypes); + SerializeExample.SerializeModels(); return; - case "example": - ShowExamples(); + case "twin": + SerializeExample.SerializeTwins(); return; } } @@ -48,12 +49,7 @@ static async Task Main(string[] args) switch (check.ToLowerInvariant()) { case "model": - var modelTypes = new[] - { - typeof(Factory), typeof(FactoryFloor), typeof(ProductionLine), - typeof(ProductionStep), typeof(ProductionStepGrinding) - }; - await ParseModels(modelTypes); + await ParseExample.ParseModels(); return; } } @@ -64,126 +60,20 @@ static async Task Main(string[] args) switch (create.ToLowerInvariant()) { case "model": - var modelTypes = new[] - { - typeof(Factory), typeof(FactoryFloor), typeof(ProductionLine), - typeof(ProductionStep), typeof(ProductionStepGrinding) - }; - await ParseModels(modelTypes); + await ParseExample.ParseModels(); return; } } ShowHelp(); } - - static async Task ParseModels(Type[] modelTypes) - { - var modelLibrary = new ModelLibrary(); - var serializer = new DigitalTwinSerializer(modelLibrary); - - var models = modelTypes.Select(x => serializer.SerializeModel(x)); - - try - { - var parser = new Microsoft.Azure.DigitalTwins.Parser.ModelParser(); - var entityInfos = await parser.ParseAsync(models); - Console.WriteLine($"PARSE SUCCESS:"); - foreach (var kvp in entityInfos) - { - Console.WriteLine( - $"[{kvp.Key}] = {kvp.Value.EntityKind} {kvp.Value.Id} ({kvp.Value.DisplayName.FirstOrDefault().Value})"); - } - } - catch (Microsoft.Azure.DigitalTwins.Parser.ParsingException ex) - { - Console.WriteLine($"PARSE FAILED: {ex.Message}"); - Console.WriteLine($"ERRORS:"); - var count = 0; - foreach (var error in ex.Errors) - { - Console.WriteLine($"{++count}. {error}"); - } - } - catch (RequestFailedException ex) - { - Console.WriteLine($"REQUEST FAILED: {ex.Message}"); - } - } - + static void ShowHelp() { - Console.WriteLine(" --show model : shows the serialized model"); - Console.WriteLine(" --show example : shows a serialized twin"); - Console.WriteLine(" --parse model : validate the model"); - Console.WriteLine(" --create model : validate and uploads the model"); - } - - static void ShowModels(Type[] modelTypes) - { - var modelLibrary = new ModelLibrary(); - var serializer = new DigitalTwinSerializer(modelLibrary); - - foreach (var modelType in modelTypes) - { - var modelDtdl = serializer.SerializeModel(modelType); - Console.WriteLine(modelDtdl); - Console.WriteLine(); - } - } - - static void ShowExamples() - { - var modelLibrary = new ModelLibrary(); - var serializer = new DigitalTwinSerializer(modelLibrary); - - var productionStepGrinding = new ProductionStepGrinding - { - ChassisTemperature = 50, - FinalStep = false, - Force = 8.0, - GrindingTime = 30, - //OperationStatus = ProductionStepStatus.Online, - PowerUsage = 100, - //StartTime = new DateTimeOffset(2021, 11, 17, 19, 57, 0, TimeSpan.FromHours(10)), - StepId = "step1", - StepName = "GrindingStep" - }; - - var productionLine = new ProductionLine - { - CurrentProductId = "production1", - LineId = "line1", - LineName = "ProductionLine", - //LineOperationStatus = ProductionLineStatus.Online, - ProductBatchNumber = 5 - }; - productionLine.RunsSteps.Add(productionStepGrinding); - - var factoryFloor = new FactoryFloor - { - FloorId = "floor1", FloorName = "FactoryFloor", Temperature = 23, ComfortIndex = 0.8 - }; - factoryFloor.RunsLines.Add(productionLine); - - var factory = new Factory - { - FactoryId = "factory1", - Country = "AU", - ZipCode = "4000", - FactoryName = "Chocolate Factory", - GeoLocation = new GeoCord { Latitude = -27.4705, Longitude = 153.026 }, - LastSupplyDate = new DateTimeOffset(2021, 11, 17, 18, 37, 0, TimeSpan.FromHours(10)) - }; - factory.Floors.Add(factoryFloor); - - var twin1Dtdl = serializer.SerializeTwin(factory); - Console.WriteLine(twin1Dtdl); - Console.WriteLine(); - - var twin2Dtdl = serializer.SerializeTwin(factory.Floors[0].RunsLines[0].RunsSteps[0]); - Console.WriteLine(twin2Dtdl); - Console.WriteLine(); + Console.WriteLine(" --serialize model : shows serialized model examples"); + Console.WriteLine(" --serialize example : shows serialized twin examples"); + Console.WriteLine(" --parse model : parse and validate the example model"); + Console.WriteLine(" --create model : parse and upload the example model"); } } } diff --git a/Examples/FactoryExample/SerializeExample.cs b/Examples/FactoryExample/SerializeExample.cs new file mode 100644 index 0000000..7188720 --- /dev/null +++ b/Examples/FactoryExample/SerializeExample.cs @@ -0,0 +1,84 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using Azure; +using FactoryExample.Devices; +using FactoryExample.Models; +using FactoryExample.Schema; +using Microsoft.Extensions.Configuration; +using Telstra.Twins.Core; +using Telstra.Twins.Services; + +namespace FactoryExample +{ + public static class SerializeExample + { + public static void SerializeModels() + { + var modelLibrary = new ModelLibrary(); + var serializer = new DigitalTwinSerializer(modelLibrary); + + foreach (var modelType in Program.ModelTypes) + { + var modelDtdl = serializer.SerializeModel(modelType); + Console.WriteLine(modelDtdl); + Console.WriteLine(); + } + } + + public static void SerializeTwins() + { + var modelLibrary = new ModelLibrary(); + var serializer = new DigitalTwinSerializer(modelLibrary); + + var productionStepGrinding = new ProductionStepGrinding + { + ChassisTemperature = 50, + FinalStep = false, + Force = 8.0, + GrindingTime = 30, + //OperationStatus = ProductionStepStatus.Online, + PowerUsage = 100, + //StartTime = new DateTimeOffset(2021, 11, 17, 19, 57, 0, TimeSpan.FromHours(10)), + StepId = "step1", + StepName = "GrindingStep" + }; + + var productionLine = new ProductionLine + { + CurrentProductId = "production1", + LineId = "line1", + LineName = "ProductionLine", + //LineOperationStatus = ProductionLineStatus.Online, + ProductBatchNumber = 5 + }; + productionLine.RunsSteps.Add(productionStepGrinding); + + var factoryFloor = new FactoryFloor + { + FloorId = "floor1", FloorName = "FactoryFloor", Temperature = 23, ComfortIndex = 0.8 + }; + factoryFloor.RunsLines.Add(productionLine); + + var factory = new Factory + { + FactoryId = "factory1", + Country = "AU", + ZipCode = "4000", + FactoryName = "Chocolate Factory", + GeoLocation = new GeoCord { Latitude = -27.4705, Longitude = 153.026 }, + LastSupplyDate = new DateTimeOffset(2021, 11, 17, 18, 37, 0, TimeSpan.FromHours(10)) + }; + factory.Floors.Add(factoryFloor); + + var twin1Dtdl = serializer.SerializeTwin(factory); + Console.WriteLine(twin1Dtdl); + Console.WriteLine(); + + var twin2Dtdl = serializer.SerializeTwin(factory.Floors[0].RunsLines[0].RunsSteps[0]); + Console.WriteLine(twin2Dtdl); + Console.WriteLine(); + } + + } +} From ff487e0512f99e096cd74fb0f7bc6efebc2583f0 Mon Sep 17 00:00:00 2001 From: Sly Gryphon Date: Wed, 15 Dec 2021 07:24:53 +1000 Subject: [PATCH 22/33] Code cleanup --- Examples/FactoryExample/ParseExample.cs | 13 +++++-------- Examples/FactoryExample/Program.cs | 21 ++++++++------------- Examples/FactoryExample/SerializeExample.cs | 5 ----- 3 files changed, 13 insertions(+), 26 deletions(-) diff --git a/Examples/FactoryExample/ParseExample.cs b/Examples/FactoryExample/ParseExample.cs index eef9be2..49be997 100644 --- a/Examples/FactoryExample/ParseExample.cs +++ b/Examples/FactoryExample/ParseExample.cs @@ -2,10 +2,7 @@ using System.Linq; using System.Threading.Tasks; using Azure; -using FactoryExample.Devices; -using FactoryExample.Models; -using FactoryExample.Schema; -using Microsoft.Extensions.Configuration; +using Microsoft.Azure.DigitalTwins.Parser; using Telstra.Twins.Core; using Telstra.Twins.Services; @@ -22,19 +19,19 @@ public static async Task ParseModels() try { - var parser = new Microsoft.Azure.DigitalTwins.Parser.ModelParser(); + var parser = new ModelParser(); var entityInfos = await parser.ParseAsync(models); - Console.WriteLine($"PARSE SUCCESS:"); + Console.WriteLine("PARSE SUCCESS:"); foreach (var kvp in entityInfos) { Console.WriteLine( $"[{kvp.Key}] = {kvp.Value.EntityKind} {kvp.Value.Id} ({kvp.Value.DisplayName.FirstOrDefault().Value})"); } } - catch (Microsoft.Azure.DigitalTwins.Parser.ParsingException ex) + catch (ParsingException ex) { Console.WriteLine($"PARSE FAILED: {ex.Message}"); - Console.WriteLine($"ERRORS:"); + Console.WriteLine("ERRORS:"); var count = 0; foreach (var error in ex.Errors) { diff --git a/Examples/FactoryExample/Program.cs b/Examples/FactoryExample/Program.cs index a86fdd0..67267e7 100644 --- a/Examples/FactoryExample/Program.cs +++ b/Examples/FactoryExample/Program.cs @@ -1,25 +1,20 @@ using System; -using System.Linq; using System.Threading.Tasks; -using Azure; using FactoryExample.Devices; using FactoryExample.Models; -using FactoryExample.Schema; using Microsoft.Extensions.Configuration; -using Telstra.Twins.Core; -using Telstra.Twins.Services; namespace FactoryExample { - class Program + internal class Program { - public static Type[] ModelTypes = new[] + public static Type[] ModelTypes = { - typeof(Factory), typeof(FactoryFloor), typeof(ProductionLine), - typeof(ProductionStep), typeof(ProductionStepGrinding) + typeof(Factory), typeof(FactoryFloor), typeof(ProductionLine), typeof(ProductionStep), + typeof(ProductionStepGrinding) }; - static async Task Main(string[] args) + private static async Task Main(string[] args) { Console.WriteLine("Digital Twin Code First Factory Example"); @@ -42,7 +37,7 @@ static async Task Main(string[] args) return; } } - + var check = configuration.GetValue("parse"); if (!string.IsNullOrWhiteSpace(check)) { @@ -67,8 +62,8 @@ static async Task Main(string[] args) ShowHelp(); } - - static void ShowHelp() + + private static void ShowHelp() { Console.WriteLine(" --serialize model : shows serialized model examples"); Console.WriteLine(" --serialize example : shows serialized twin examples"); diff --git a/Examples/FactoryExample/SerializeExample.cs b/Examples/FactoryExample/SerializeExample.cs index 7188720..5531acf 100644 --- a/Examples/FactoryExample/SerializeExample.cs +++ b/Examples/FactoryExample/SerializeExample.cs @@ -1,11 +1,7 @@ using System; -using System.Linq; -using System.Threading.Tasks; -using Azure; using FactoryExample.Devices; using FactoryExample.Models; using FactoryExample.Schema; -using Microsoft.Extensions.Configuration; using Telstra.Twins.Core; using Telstra.Twins.Services; @@ -79,6 +75,5 @@ public static void SerializeTwins() Console.WriteLine(twin2Dtdl); Console.WriteLine(); } - } } From d298cea92130cade553af0b1d5d25a6cc57bb5eb Mon Sep 17 00:00:00 2001 From: Sly Gryphon Date: Wed, 15 Dec 2021 07:26:19 +1000 Subject: [PATCH 23/33] Mode code cleanup --- Examples/FactoryExample/Devices/ProductionStep.cs | 4 ++-- Examples/FactoryExample/Devices/ProductionStepGrinding.cs | 3 ++- Examples/FactoryExample/Models/Factory.cs | 4 ++-- Examples/FactoryExample/Models/FactoryFloor.cs | 6 +++--- Examples/FactoryExample/Models/ProductionLine.cs | 2 +- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Examples/FactoryExample/Devices/ProductionStep.cs b/Examples/FactoryExample/Devices/ProductionStep.cs index ba99cba..abdff26 100644 --- a/Examples/FactoryExample/Devices/ProductionStep.cs +++ b/Examples/FactoryExample/Devices/ProductionStep.cs @@ -8,9 +8,9 @@ namespace FactoryExample.Devices public class ProductionStep : TwinBase { // ContainsEquipment - + [TwinProperty] public bool FinalStep { get; set; } - + // HasConnectedDevices //[TwinProperty] public ProductionStepStatus OperationStatus { get; set; } diff --git a/Examples/FactoryExample/Devices/ProductionStepGrinding.cs b/Examples/FactoryExample/Devices/ProductionStepGrinding.cs index 22a152c..b036e27 100644 --- a/Examples/FactoryExample/Devices/ProductionStepGrinding.cs +++ b/Examples/FactoryExample/Devices/ProductionStepGrinding.cs @@ -7,7 +7,8 @@ namespace FactoryExample.Devices ExtendsModelId = "dtmi:factoryexample:devices:productionstep;1")] public class ProductionStepGrinding : ProductionStep { - [TwinProperty(SemanticType = SemanticType.Temperature, Unit = TemperatureUnit.DegreeCelsius, Writable = true)] + [TwinProperty(SemanticType = SemanticType.Temperature, Unit = TemperatureUnit.DegreeCelsius, + Writable = true)] public double? ChassisTemperature { get; set; } [TwinProperty(SemanticType = SemanticType.Force, Unit = ForceUnit.Newton)] diff --git a/Examples/FactoryExample/Models/Factory.cs b/Examples/FactoryExample/Models/Factory.cs index 2bd8984..870dab7 100644 --- a/Examples/FactoryExample/Models/Factory.cs +++ b/Examples/FactoryExample/Models/Factory.cs @@ -14,14 +14,14 @@ public class Factory : TwinBase [TwinProperty] public string? FactoryId { get; set; } [TwinProperty(Writable = true)] public string? FactoryName { get; set; } - + [TwinRelationship(DisplayName = "Has Floors")] public IList Floors { get; } = new List(); [TwinProperty] public GeoCord? GeoLocation { get; set; } [TwinProperty] public DateTimeOffset LastSupplyDate { get; set; } - + // ServesRetailer // SuppliedBy // TransportationBy diff --git a/Examples/FactoryExample/Models/FactoryFloor.cs b/Examples/FactoryExample/Models/FactoryFloor.cs index e0a850e..fd99142 100644 --- a/Examples/FactoryExample/Models/FactoryFloor.cs +++ b/Examples/FactoryExample/Models/FactoryFloor.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using MediatR; using Telstra.Twins; using Telstra.Twins.Attributes; using Telstra.Twins.Semantics; @@ -15,13 +14,14 @@ public class FactoryFloor : TwinBase // FloorHasRooms // FloorHasZones - + [TwinProperty(Writable = true)] public string? FloorName { get; set; } [TwinRelationship(DisplayName = "Runs Production Lines")] public IList RunsLines { get; } = new List(); - [TwinProperty(SemanticType = SemanticType.Temperature, Unit = TemperatureUnit.DegreeCelsius, Writable = true)] + [TwinProperty(SemanticType = SemanticType.Temperature, Unit = TemperatureUnit.DegreeCelsius, + Writable = true)] public double? Temperature { get; set; } } } diff --git a/Examples/FactoryExample/Models/ProductionLine.cs b/Examples/FactoryExample/Models/ProductionLine.cs index c6a94c8..cb47cb5 100644 --- a/Examples/FactoryExample/Models/ProductionLine.cs +++ b/Examples/FactoryExample/Models/ProductionLine.cs @@ -9,7 +9,7 @@ namespace FactoryExample.Models public class ProductionLine : TwinBase { // ContainsEquipment - + [TwinProperty(Writable = true)] public string? CurrentProductId { get; set; } [TwinProperty(Writable = true)] public string? LineId { get; set; } From 4d5fed9a16413130a8a88f4beae060a8b7280406 Mon Sep 17 00:00:00 2001 From: Sly Gryphon Date: Wed, 15 Dec 2021 22:31:42 +1000 Subject: [PATCH 24/33] Reorganise scripts, add data permissions --- ...ce.ps1 => 0002 - Create Digital Twins service.ps1} | 11 +++++++++++ ...- Create IOT hub.ps1 => 0003 - Create IOT hub.ps1} | 0 2 files changed, 11 insertions(+) rename Examples/FactoryExample/infrastructure/{0003 - Create Digital Twins service.ps1 => 0002 - Create Digital Twins service.ps1} (55%) rename Examples/FactoryExample/infrastructure/{0002 - Create IOT hub.ps1 => 0003 - Create IOT hub.ps1} (100%) diff --git a/Examples/FactoryExample/infrastructure/0003 - Create Digital Twins service.ps1 b/Examples/FactoryExample/infrastructure/0002 - Create Digital Twins service.ps1 similarity index 55% rename from Examples/FactoryExample/infrastructure/0003 - Create Digital Twins service.ps1 rename to Examples/FactoryExample/infrastructure/0002 - Create Digital Twins service.ps1 index c7e57d8..1c3302a 100644 --- a/Examples/FactoryExample/infrastructure/0003 - Create Digital Twins service.ps1 +++ b/Examples/FactoryExample/infrastructure/0002 - Create Digital Twins service.ps1 @@ -8,13 +8,24 @@ param ( ) $appName = 'codefirsttwins' +$roleName = 'Azure Digital Twins Data Owner' $rgName = "rg-$appName-$Environment-001".ToLowerInvariant() $rg = Get-AzResourceGroup -Name $rgName $dtName = "dt-$appName-$OrgId-$Environment".ToLowerInvariant() +$contextAccount = (Get-AzContext).Account + Write-Verbose "Creating digital twins service $dtName in resource group $rgName" New-AzDigitalTwinsInstance -ResourceName $dtName ` -ResourceGroupName $rgName -Location $rg.Location -Tag $rg.Tags + +Write-Verbose "Assigning data permissions to digital twins service $dtName to $contextAccount" + +$user = Get-AzADUser -UserPrincipalName $contextAccount +$dti = Get-AzDigitalTwinsInstance -ResourceGroupName $rgName -ResourceName $dtName + +New-AzRoleAssignment -ObjectId $user.Id -RoleDefinitionName $roleName -Scope $dti.Id + diff --git a/Examples/FactoryExample/infrastructure/0002 - Create IOT hub.ps1 b/Examples/FactoryExample/infrastructure/0003 - Create IOT hub.ps1 similarity index 100% rename from Examples/FactoryExample/infrastructure/0002 - Create IOT hub.ps1 rename to Examples/FactoryExample/infrastructure/0003 - Create IOT hub.ps1 From 7a168822123fe8a29fc56a7b3f63e669fbca86cd Mon Sep 17 00:00:00 2001 From: Sly Gryphon Date: Wed, 15 Dec 2021 22:59:34 +1000 Subject: [PATCH 25/33] Add create function; update readme instructions - can successfully create model --- Examples/FactoryExample/CreateExample.cs | 60 +++++++++++++++++ Examples/FactoryExample/FactoryExample.csproj | 4 ++ Examples/FactoryExample/Program.cs | 4 +- Examples/FactoryExample/ReadMe.md | 66 +++++++++++++++---- 4 files changed, 119 insertions(+), 15 deletions(-) create mode 100644 Examples/FactoryExample/CreateExample.cs diff --git a/Examples/FactoryExample/CreateExample.cs b/Examples/FactoryExample/CreateExample.cs new file mode 100644 index 0000000..8de9396 --- /dev/null +++ b/Examples/FactoryExample/CreateExample.cs @@ -0,0 +1,60 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Threading.Tasks; +using Azure; +using Azure.DigitalTwins.Core; +using Azure.Identity; +using Microsoft.Azure.DigitalTwins.Parser; +using Telstra.Twins.Core; +using Telstra.Twins.Services; + +namespace FactoryExample +{ + public class CreateExample + { + //public static async Task CreateModels(string tenantId, string clientId, string clientSecret, string adtEndpoint) + public static async Task CreateModels(string adtEndpoint) + { + 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); + Console.WriteLine("CREATE SUCCESS"); + foreach (var modelData in response.Value) + { + Console.WriteLine($"{modelData.Id}: {modelData.LanguageDisplayNames.FirstOrDefault().Value}"); + } + } + catch (Exception ex) + { + Console.WriteLine($"CREATE FAILED: {ex.Message}"); + } + } + + 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(includeInteractiveCredentials: true); + + var client = new DigitalTwinsClient( + new Uri(adtEndpoint), + tokenCredential); + + return client; + } + } +} diff --git a/Examples/FactoryExample/FactoryExample.csproj b/Examples/FactoryExample/FactoryExample.csproj index fd895e1..864e46f 100644 --- a/Examples/FactoryExample/FactoryExample.csproj +++ b/Examples/FactoryExample/FactoryExample.csproj @@ -10,4 +10,8 @@ + + + + diff --git a/Examples/FactoryExample/Program.cs b/Examples/FactoryExample/Program.cs index 67267e7..0ecad21 100644 --- a/Examples/FactoryExample/Program.cs +++ b/Examples/FactoryExample/Program.cs @@ -55,7 +55,9 @@ private static async Task Main(string[] args) switch (create.ToLowerInvariant()) { case "model": + var adtEndpoint = configuration.GetValue("endpoint"); await ParseExample.ParseModels(); + await CreateExample.CreateModels(adtEndpoint); return; } } @@ -68,7 +70,7 @@ private static void ShowHelp() Console.WriteLine(" --serialize model : shows serialized model examples"); Console.WriteLine(" --serialize example : shows serialized twin examples"); Console.WriteLine(" --parse model : parse and validate the example model"); - Console.WriteLine(" --create model : parse and upload the example model"); + Console.WriteLine(" --create model --endpoint : parse and upload the example model"); } } } diff --git a/Examples/FactoryExample/ReadMe.md b/Examples/FactoryExample/ReadMe.md index 9b23c30..b811616 100644 --- a/Examples/FactoryExample/ReadMe.md +++ b/Examples/FactoryExample/ReadMe.md @@ -8,29 +8,67 @@ Requirements: Based on https://github.com/Azure-Samples/digital-twins-samples/tree/master/HandsOnLab +Create infrastructure +--------------------- -```pwsh -az login -az account set --subscription "" +You need to create a digital twins instance in Azure to deploy the model to. There is a +script `deploy-infrastructure.ps1` that will created the needed resources. + +To run the script you need to load the required PowerShell modules, then connect to your +Azure account and set the context for the subscription you want to use, then run the +script. + +``` pwsh + Install-Module -Name Az -Scope CurrentUser -Force + Install-Module -Name Az.DigitalTwins -Scope CurrentUser -Force + Register-AzResourceProvider -ProviderNamespace Microsoft.DigitalTwins + + Connect-AzAccount + Set-AzContext -SubscriptionId $SubscriptionId + + $VerbosePreference = 'Continue' + ./deploy-infrastructure.ps1 ``` +Running the example +------------------- +To see the example serialized model: + +``` +dotnet run -- --serialize model ``` -az group create --location --name -az dt create --dt-name --resource-group --location -az dt show --dt-name . -az iot hub create --name --resource-group --sku S1 +To see the example serialized twin instances: + +``` +dotnet run -- --serialize twin ``` +To run parse and validate the model with `Microsoft.Azure.DigitalTwins.Parser`: +``` +dotnet run -- --parse model +``` +To upload the model to Azure: + +``` pwsh +$rgName = "rg-codefirsttwins-dev-001" +$dtName = "dt-codefirsttwins-0x$((Get-AzContext).Subscription.Id.Substring(0,4))-dev" +$hostName = (Get-AzDigitalTwinsInstance -ResourceGroupName $rgName -ResourceName $dtName).HostName +dotnet run -- --create model --endpoint "https://$hostName" ``` -Set-AzContext -SubscriptionId 00000000-0000-0000-0000-000000000000 -Register-AzResourceProvider -ProviderNamespace Microsoft.DigitalTwins -Install-Module -Name Az.DigitalTwins -New-AzResourceGroup -Name -Location -New-AzDigitalTwinsInstance -ResourceGroupName -ResourceName -Location -Get-AzDigitalTwinsInstance -ResourceGroupName -ResourceName | - Select-Object -Property * + + +Cleanup +------- + +After running the example, you can clean up the Azure resources (to save money). + +``` pwsh + $VerbosePreference = 'Continue' + ./remove-infrastructure.ps1 +``` + From 5027fbe8f91f89dcab2cb7be5ff1e065ce3f3c74 Mon Sep 17 00:00:00 2001 From: Sly Gryphon Date: Wed, 15 Dec 2021 23:00:58 +1000 Subject: [PATCH 26/33] Can successfully create a twin instance --- Examples/FactoryExample/CreateExample.cs | 32 ++++++++++- Examples/FactoryExample/ParseExample.cs | 3 +- Examples/FactoryExample/Program.cs | 61 +++++++++++++++++++-- Examples/FactoryExample/SerializeExample.cs | 40 +------------- 4 files changed, 89 insertions(+), 47 deletions(-) diff --git a/Examples/FactoryExample/CreateExample.cs b/Examples/FactoryExample/CreateExample.cs index 8de9396..b4f98fc 100644 --- a/Examples/FactoryExample/CreateExample.cs +++ b/Examples/FactoryExample/CreateExample.cs @@ -1,6 +1,8 @@ using System; using System.ComponentModel.DataAnnotations; using System.Linq; +using System.Text.Json; +using System.Threading; using System.Threading.Tasks; using Azure; using Azure.DigitalTwins.Core; @@ -14,7 +16,7 @@ namespace FactoryExample public class CreateExample { //public static async Task CreateModels(string tenantId, string clientId, string clientSecret, string adtEndpoint) - public static async Task CreateModels(string adtEndpoint) + public static async Task CreateModelsAsync(string adtEndpoint, CancellationToken cancellationToken) { var modelLibrary = new ModelLibrary(); var serializer = new DigitalTwinSerializer(modelLibrary); @@ -25,8 +27,8 @@ public static async Task CreateModels(string adtEndpoint) { //var client = GetDigitalTwinsClient(tenantId, clientId, clientSecret, adtEndpoint); var client = GetDigitalTwinsClient(adtEndpoint); - var response = await client.CreateModelsAsync(models); - Console.WriteLine("CREATE SUCCESS"); + 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}"); @@ -38,6 +40,30 @@ public static async Task CreateModels(string adtEndpoint) } } + 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); + + // Twin 1 + var dtdl = serializer.SerializeTwin(factory); + var basicDigitalTwin = JsonSerializer.Deserialize(dtdl); + Response response = await client.CreateOrReplaceDigitalTwinAsync(factory.FactoryId, basicDigitalTwin, null, cancellationToken); + Console.WriteLine("CREATE MODELS SUCCESS: Id={0}, ETag={1}", response.Value.Id, response.Value.ETag); + } + catch (Exception ex) + { + Console.WriteLine($"CREATE FAILED: {ex.Message}"); + } + } + private static DigitalTwinsClient GetDigitalTwinsClient(string adtEndpoint) //private static DigitalTwinsClient GetDigitalTwinsClient(string tenantId, string clientId, string clientSecret, string adtEndpoint) { diff --git a/Examples/FactoryExample/ParseExample.cs b/Examples/FactoryExample/ParseExample.cs index 49be997..3c5dedc 100644 --- a/Examples/FactoryExample/ParseExample.cs +++ b/Examples/FactoryExample/ParseExample.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Threading; using System.Threading.Tasks; using Azure; using Microsoft.Azure.DigitalTwins.Parser; @@ -10,7 +11,7 @@ namespace FactoryExample { public static class ParseExample { - public static async Task ParseModels() + public static async Task ParseModelsAsync(CancellationToken cancellationToken) { var modelLibrary = new ModelLibrary(); var serializer = new DigitalTwinSerializer(modelLibrary); diff --git a/Examples/FactoryExample/Program.cs b/Examples/FactoryExample/Program.cs index 0ecad21..20a0829 100644 --- a/Examples/FactoryExample/Program.cs +++ b/Examples/FactoryExample/Program.cs @@ -1,7 +1,9 @@ using System; +using System.Threading; using System.Threading.Tasks; using FactoryExample.Devices; using FactoryExample.Models; +using FactoryExample.Schema; using Microsoft.Extensions.Configuration; namespace FactoryExample @@ -44,7 +46,7 @@ private static async Task Main(string[] args) switch (check.ToLowerInvariant()) { case "model": - await ParseExample.ParseModels(); + await ParseExample.ParseModelsAsync(CancellationToken.None); return; } } @@ -52,12 +54,15 @@ private static async Task Main(string[] args) var create = configuration.GetValue("create"); if (!string.IsNullOrWhiteSpace(create)) { + var adtEndpoint = configuration.GetValue("endpoint"); switch (create.ToLowerInvariant()) { case "model": - var adtEndpoint = configuration.GetValue("endpoint"); - await ParseExample.ParseModels(); - await CreateExample.CreateModels(adtEndpoint); + await ParseExample.ParseModelsAsync(CancellationToken.None); + await CreateExample.CreateModelsAsync(adtEndpoint, CancellationToken.None); + return; + case "twin": + await CreateExample.CreateTwinsAsync(adtEndpoint, CancellationToken.None); return; } } @@ -65,6 +70,54 @@ private static async Task Main(string[] args) ShowHelp(); } + public static Factory CreateFactoryTwin() + { + var productionStepGrinding = new ProductionStepGrinding + { + ChassisTemperature = 50, + FinalStep = false, + Force = 8.0, + GrindingTime = 30, + //OperationStatus = ProductionStepStatus.Online, + PowerUsage = 100, + //StartTime = new DateTimeOffset(2021, 11, 17, 19, 57, 0, TimeSpan.FromHours(10)), + StepId = "step1", + StepName = "GrindingStep" + }; + + var productionLine = new ProductionLine + { + CurrentProductId = "production1", + LineId = "line1", + LineName = "ProductionLine", + //LineOperationStatus = ProductionLineStatus.Online, + ProductBatchNumber = 5 + }; + productionLine.RunsSteps.Add(productionStepGrinding); + + var factoryFloor = new FactoryFloor + { + ComfortIndex = 0.8, + FloorId = "floor1", + FloorName = "FactoryFloor", + Temperature = 23 + }; + factoryFloor.RunsLines.Add(productionLine); + + var factory = new Factory + { + Country = "AU", + FactoryId = "factory1", + FactoryName = "Chocolate Factory", + GeoLocation = new GeoCord { Latitude = -27.4705, Longitude = 153.026 }, + LastSupplyDate = new DateTimeOffset(2021, 11, 17, 18, 37, 0, TimeSpan.FromHours(10)), + Tags = String.Empty, + ZipCode = "4000" + }; + factory.Floors.Add(factoryFloor); + return factory; + } + private static void ShowHelp() { Console.WriteLine(" --serialize model : shows serialized model examples"); diff --git a/Examples/FactoryExample/SerializeExample.cs b/Examples/FactoryExample/SerializeExample.cs index 5531acf..198bf0d 100644 --- a/Examples/FactoryExample/SerializeExample.cs +++ b/Examples/FactoryExample/SerializeExample.cs @@ -27,45 +27,7 @@ public static void SerializeTwins() var modelLibrary = new ModelLibrary(); var serializer = new DigitalTwinSerializer(modelLibrary); - var productionStepGrinding = new ProductionStepGrinding - { - ChassisTemperature = 50, - FinalStep = false, - Force = 8.0, - GrindingTime = 30, - //OperationStatus = ProductionStepStatus.Online, - PowerUsage = 100, - //StartTime = new DateTimeOffset(2021, 11, 17, 19, 57, 0, TimeSpan.FromHours(10)), - StepId = "step1", - StepName = "GrindingStep" - }; - - var productionLine = new ProductionLine - { - CurrentProductId = "production1", - LineId = "line1", - LineName = "ProductionLine", - //LineOperationStatus = ProductionLineStatus.Online, - ProductBatchNumber = 5 - }; - productionLine.RunsSteps.Add(productionStepGrinding); - - var factoryFloor = new FactoryFloor - { - FloorId = "floor1", FloorName = "FactoryFloor", Temperature = 23, ComfortIndex = 0.8 - }; - factoryFloor.RunsLines.Add(productionLine); - - var factory = new Factory - { - FactoryId = "factory1", - Country = "AU", - ZipCode = "4000", - FactoryName = "Chocolate Factory", - GeoLocation = new GeoCord { Latitude = -27.4705, Longitude = 153.026 }, - LastSupplyDate = new DateTimeOffset(2021, 11, 17, 18, 37, 0, TimeSpan.FromHours(10)) - }; - factory.Floors.Add(factoryFloor); + var factory = Program.CreateFactoryTwin(); var twin1Dtdl = serializer.SerializeTwin(factory); Console.WriteLine(twin1Dtdl); From 0763c13f9cbf7e5e1ad62f15ff3a9a297e2df0dc Mon Sep 17 00:00:00 2001 From: Sly Gryphon Date: Wed, 15 Dec 2021 23:09:46 +1000 Subject: [PATCH 27/33] Update readme with instructions to view results in explorer --- Examples/FactoryExample/ReadMe.md | 35 ++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/Examples/FactoryExample/ReadMe.md b/Examples/FactoryExample/ReadMe.md index b811616..ed82747 100644 --- a/Examples/FactoryExample/ReadMe.md +++ b/Examples/FactoryExample/ReadMe.md @@ -30,8 +30,21 @@ script. ./deploy-infrastructure.ps1 ``` -Running the example -------------------- +Digital Twins Explorer +---------------------- + +After you have created the infrastructure, open `https://portal.azure.com/` and go to the resource group. + +Open the Azure Digital Twins resource. + +Copy the Host name, and then open the Azure Digital Twins Explorer (preview). + +For the Azure Digital Twins URL, use `https://`, with the Host name copied from above. + +The explorer should start out empty (see below). + +Running basic checks +-------------------- To see the example serialized model: @@ -51,7 +64,10 @@ To run parse and validate the model with `Microsoft.Azure.DigitalTwins.Parser`: dotnet run -- --parse model ``` -To upload the model to Azure: +Running the example to create models and twins +---------------------------------------------- + +To upload the models to Azure: ``` pwsh $rgName = "rg-codefirsttwins-dev-001" @@ -60,6 +76,16 @@ $hostName = (Get-AzDigitalTwinsInstance -ResourceGroupName $rgName -ResourceName dotnet run -- --create model --endpoint "https://$hostName" ``` +After this, if you refresh the Models in Digital Twins Explorer, you will see the uploaded models. + +You then need to upload the Twin instances: + +``` pwsh +dotnet run -- --create twin --endpoint "https://$hostName" +``` + +To see the Twin instances, ensure the query explorer has the default query `SELECT * FROM digitaltwins`, +and then click Run Query. The twin instances should appear in the Twins list and Twin Graph. Cleanup ------- @@ -67,8 +93,7 @@ Cleanup After running the example, you can clean up the Azure resources (to save money). ``` pwsh - $VerbosePreference = 'Continue' - ./remove-infrastructure.ps1 +./remove-infrastructure.ps1 ``` From e77ade9e8893c339cda274d61f8d6adbe85a3e85 Mon Sep 17 00:00:00 2001 From: Sly Gryphon Date: Thu, 16 Dec 2021 06:50:31 +1000 Subject: [PATCH 28/33] Code cleanup --- DigitalTwins-CodeFirst-dotnet.sln.DotSettings | 1 + Examples/FactoryExample/CreateExample.cs | 19 ++-- Examples/FactoryExample/Program.cs | 99 +++++++++---------- Examples/FactoryExample/SerializeExample.cs | 3 - 4 files changed, 59 insertions(+), 63 deletions(-) diff --git a/DigitalTwins-CodeFirst-dotnet.sln.DotSettings b/DigitalTwins-CodeFirst-dotnet.sln.DotSettings index c69b61e..6881f4a 100644 --- a/DigitalTwins-CodeFirst-dotnet.sln.DotSettings +++ b/DigitalTwins-CodeFirst-dotnet.sln.DotSettings @@ -1,2 +1,3 @@  + True True \ No newline at end of file diff --git a/Examples/FactoryExample/CreateExample.cs b/Examples/FactoryExample/CreateExample.cs index b4f98fc..9031a21 100644 --- a/Examples/FactoryExample/CreateExample.cs +++ b/Examples/FactoryExample/CreateExample.cs @@ -1,19 +1,16 @@ using System; -using System.ComponentModel.DataAnnotations; using System.Linq; using System.Text.Json; using System.Threading; using System.Threading.Tasks; -using Azure; using Azure.DigitalTwins.Core; using Azure.Identity; -using Microsoft.Azure.DigitalTwins.Parser; using Telstra.Twins.Core; using Telstra.Twins.Services; namespace FactoryExample { - public class CreateExample + 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) @@ -31,7 +28,8 @@ public static async Task CreateModelsAsync(string adtEndpoint, CancellationToken Console.WriteLine("CREATE MODELS SUCCESS"); foreach (var modelData in response.Value) { - Console.WriteLine($"{modelData.Id}: {modelData.LanguageDisplayNames.FirstOrDefault().Value}"); + Console.WriteLine( + $"{modelData.Id}: {modelData.LanguageDisplayNames.FirstOrDefault().Value}"); } } catch (Exception ex) @@ -55,8 +53,11 @@ public static async Task CreateTwinsAsync(string adtEndpoint, CancellationToken // Twin 1 var dtdl = serializer.SerializeTwin(factory); var basicDigitalTwin = JsonSerializer.Deserialize(dtdl); - Response response = await client.CreateOrReplaceDigitalTwinAsync(factory.FactoryId, basicDigitalTwin, null, cancellationToken); - Console.WriteLine("CREATE MODELS SUCCESS: Id={0}, ETag={1}", response.Value.Id, response.Value.ETag); + var response = + await client.CreateOrReplaceDigitalTwinAsync(factory.FactoryId, + basicDigitalTwin!, null, cancellationToken); + Console.WriteLine("CREATE MODELS SUCCESS: Id={0}, ETag={1}", response.Value.Id, + response.Value.ETag); } catch (Exception ex) { @@ -65,7 +66,7 @@ public static async Task CreateTwinsAsync(string adtEndpoint, CancellationToken } private static DigitalTwinsClient GetDigitalTwinsClient(string adtEndpoint) - //private static DigitalTwinsClient GetDigitalTwinsClient(string tenantId, string clientId, string clientSecret, 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); @@ -74,7 +75,7 @@ private static DigitalTwinsClient GetDigitalTwinsClient(string adtEndpoint) // 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(includeInteractiveCredentials: true); + var tokenCredential = new DefaultAzureCredential(true); var client = new DigitalTwinsClient( new Uri(adtEndpoint), diff --git a/Examples/FactoryExample/Program.cs b/Examples/FactoryExample/Program.cs index 20a0829..052992e 100644 --- a/Examples/FactoryExample/Program.cs +++ b/Examples/FactoryExample/Program.cs @@ -8,15 +8,60 @@ namespace FactoryExample { - internal class Program + public static class Program { - public static Type[] ModelTypes = + public static readonly Type[] ModelTypes = { typeof(Factory), typeof(FactoryFloor), typeof(ProductionLine), typeof(ProductionStep), typeof(ProductionStepGrinding) }; - private static async Task Main(string[] args) + public static Factory CreateFactoryTwin() + { + var productionStepGrinding = new ProductionStepGrinding + { + ChassisTemperature = 50, + FinalStep = false, + Force = 8.0, + GrindingTime = 30, + //OperationStatus = ProductionStepStatus.Online, + PowerUsage = 100, + //StartTime = new DateTimeOffset(2021, 11, 17, 19, 57, 0, TimeSpan.FromHours(10)), + StepId = "step1", + StepName = "GrindingStep" + }; + + var productionLine = new ProductionLine + { + CurrentProductId = "production1", + LineId = "line1", + LineName = "ProductionLine", + //LineOperationStatus = ProductionLineStatus.Online, + ProductBatchNumber = 5 + }; + productionLine.RunsSteps.Add(productionStepGrinding); + + var factoryFloor = new FactoryFloor + { + ComfortIndex = 0.8, FloorId = "floor1", FloorName = "FactoryFloor", Temperature = 23 + }; + factoryFloor.RunsLines.Add(productionLine); + + var factory = new Factory + { + Country = "AU", + FactoryId = "factory1", + FactoryName = "Chocolate Factory", + GeoLocation = new GeoCord { Latitude = -27.4705, Longitude = 153.026 }, + LastSupplyDate = new DateTimeOffset(2021, 11, 17, 18, 37, 0, TimeSpan.FromHours(10)), + Tags = String.Empty, + ZipCode = "4000" + }; + factory.Floors.Add(factoryFloor); + return factory; + } + + public static async Task Main(string[] args) { Console.WriteLine("Digital Twin Code First Factory Example"); @@ -70,54 +115,6 @@ private static async Task Main(string[] args) ShowHelp(); } - public static Factory CreateFactoryTwin() - { - var productionStepGrinding = new ProductionStepGrinding - { - ChassisTemperature = 50, - FinalStep = false, - Force = 8.0, - GrindingTime = 30, - //OperationStatus = ProductionStepStatus.Online, - PowerUsage = 100, - //StartTime = new DateTimeOffset(2021, 11, 17, 19, 57, 0, TimeSpan.FromHours(10)), - StepId = "step1", - StepName = "GrindingStep" - }; - - var productionLine = new ProductionLine - { - CurrentProductId = "production1", - LineId = "line1", - LineName = "ProductionLine", - //LineOperationStatus = ProductionLineStatus.Online, - ProductBatchNumber = 5 - }; - productionLine.RunsSteps.Add(productionStepGrinding); - - var factoryFloor = new FactoryFloor - { - ComfortIndex = 0.8, - FloorId = "floor1", - FloorName = "FactoryFloor", - Temperature = 23 - }; - factoryFloor.RunsLines.Add(productionLine); - - var factory = new Factory - { - Country = "AU", - FactoryId = "factory1", - FactoryName = "Chocolate Factory", - GeoLocation = new GeoCord { Latitude = -27.4705, Longitude = 153.026 }, - LastSupplyDate = new DateTimeOffset(2021, 11, 17, 18, 37, 0, TimeSpan.FromHours(10)), - Tags = String.Empty, - ZipCode = "4000" - }; - factory.Floors.Add(factoryFloor); - return factory; - } - private static void ShowHelp() { Console.WriteLine(" --serialize model : shows serialized model examples"); diff --git a/Examples/FactoryExample/SerializeExample.cs b/Examples/FactoryExample/SerializeExample.cs index 198bf0d..4954e49 100644 --- a/Examples/FactoryExample/SerializeExample.cs +++ b/Examples/FactoryExample/SerializeExample.cs @@ -1,7 +1,4 @@ using System; -using FactoryExample.Devices; -using FactoryExample.Models; -using FactoryExample.Schema; using Telstra.Twins.Core; using Telstra.Twins.Services; From ad70021c2ab6629bae1568c37c9ca8bd9ad27142 Mon Sep 17 00:00:00 2001 From: Sly Gryphon Date: Sat, 18 Dec 2021 11:35:44 +1000 Subject: [PATCH 29/33] Second twin instance, with relationship --- Examples/FactoryExample/CreateExample.cs | 37 +++++++++++++++++++----- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/Examples/FactoryExample/CreateExample.cs b/Examples/FactoryExample/CreateExample.cs index 9031a21..139e6f3 100644 --- a/Examples/FactoryExample/CreateExample.cs +++ b/Examples/FactoryExample/CreateExample.cs @@ -50,14 +50,37 @@ public static async Task CreateTwinsAsync(string adtEndpoint, CancellationToken //var client = GetDigitalTwinsClient(tenantId, clientId, clientSecret, adtEndpoint); var client = GetDigitalTwinsClient(adtEndpoint); - // Twin 1 - var dtdl = serializer.SerializeTwin(factory); - var basicDigitalTwin = JsonSerializer.Deserialize(dtdl); - var response = + // Twin 1 + var factoryDtdl = serializer.SerializeTwin(factory); + var factoryDigitalTwin = JsonSerializer.Deserialize(factoryDtdl); + var factoryResponse = await client.CreateOrReplaceDigitalTwinAsync(factory.FactoryId, - basicDigitalTwin!, null, cancellationToken); - Console.WriteLine("CREATE MODELS SUCCESS: Id={0}, ETag={1}", response.Value.Id, - response.Value.ETag); + factoryDigitalTwin!, null, cancellationToken); + Console.WriteLine("CREATE TWIN SUCCESS: Id={0}, ETag={1}", factoryResponse.Value.Id, + factoryResponse.Value.ETag); + + // Twin 2 + var floor0Dtdl = serializer.SerializeTwin(factory.Floors[0]); + var floor0DigitalTwin = JsonSerializer.Deserialize(floor0Dtdl); + var floor0Response = + await client.CreateOrReplaceDigitalTwinAsync(factory.Floors[0].FloorId, + floor0DigitalTwin!, null, cancellationToken); + Console.WriteLine("CREATE TWIN SUCCESS: Id={0}, ETag={1}", floor0Response.Value.Id, + floor0Response.Value.ETag); + + // Relationship + var floor0Relationship = new BasicRelationship() + { + Id = $"{factory.FactoryId}_{factory.Floors[0].FloorId}", + Name = "floors", + SourceId = factory.FactoryId, + TargetId = factory.Floors[0].FloorId + }; + var floor0RelationshipResponse = + await client.CreateOrReplaceRelationshipAsync(factory.FactoryId, floor0Relationship.Id, + floor0Relationship, null, cancellationToken); + Console.WriteLine("CREATE RELATIONSHIP SUCCESS: Id={0}, ETag={1}", floor0RelationshipResponse.Value.Id, + floor0RelationshipResponse.Value.ETag); } catch (Exception ex) { From 5d43e35bb262441e3d3d0d6884dabc91ccadc2b0 Mon Sep 17 00:00:00 2001 From: Sly Gryphon Date: Sat, 18 Dec 2021 11:37:48 +1000 Subject: [PATCH 30/33] Code cleanup --- Examples/FactoryExample/CreateExample.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Examples/FactoryExample/CreateExample.cs b/Examples/FactoryExample/CreateExample.cs index 139e6f3..218d486 100644 --- a/Examples/FactoryExample/CreateExample.cs +++ b/Examples/FactoryExample/CreateExample.cs @@ -58,7 +58,7 @@ await client.CreateOrReplaceDigitalTwinAsync(factory.FactoryId, factoryDigitalTwin!, null, cancellationToken); Console.WriteLine("CREATE TWIN SUCCESS: Id={0}, ETag={1}", factoryResponse.Value.Id, factoryResponse.Value.ETag); - + // Twin 2 var floor0Dtdl = serializer.SerializeTwin(factory.Floors[0]); var floor0DigitalTwin = JsonSerializer.Deserialize(floor0Dtdl); @@ -67,9 +67,9 @@ await client.CreateOrReplaceDigitalTwinAsync(factory.Floors[0].FloorId, floor0DigitalTwin!, null, cancellationToken); Console.WriteLine("CREATE TWIN SUCCESS: Id={0}, ETag={1}", floor0Response.Value.Id, floor0Response.Value.ETag); - + // Relationship - var floor0Relationship = new BasicRelationship() + var floor0Relationship = new BasicRelationship { Id = $"{factory.FactoryId}_{factory.Floors[0].FloorId}", Name = "floors", @@ -79,7 +79,8 @@ await client.CreateOrReplaceDigitalTwinAsync(factory.Floors[0].FloorId, var floor0RelationshipResponse = await client.CreateOrReplaceRelationshipAsync(factory.FactoryId, floor0Relationship.Id, floor0Relationship, null, cancellationToken); - Console.WriteLine("CREATE RELATIONSHIP SUCCESS: Id={0}, ETag={1}", floor0RelationshipResponse.Value.Id, + Console.WriteLine("CREATE RELATIONSHIP SUCCESS: Id={0}, ETag={1}", + floor0RelationshipResponse.Value.Id, floor0RelationshipResponse.Value.ETag); } catch (Exception ex) From 15cab5316a22fe399444cb722d37a90ab207ee9f Mon Sep 17 00:00:00 2001 From: Sly Gryphon Date: Sat, 18 Dec 2021 12:21:28 +1000 Subject: [PATCH 31/33] Create all example entities --- Examples/FactoryExample/CreateExample.cs | 109 +++++++++++++----- .../Devices/ProductionStepFanning.cs | 23 ++++ .../Devices/ProductionStepMoulding.cs | 17 +++ Examples/FactoryExample/Program.cs | 59 +++++++--- 4 files changed, 161 insertions(+), 47 deletions(-) create mode 100644 Examples/FactoryExample/Devices/ProductionStepFanning.cs create mode 100644 Examples/FactoryExample/Devices/ProductionStepMoulding.cs diff --git a/Examples/FactoryExample/CreateExample.cs b/Examples/FactoryExample/CreateExample.cs index 218d486..ce9cdb8 100644 --- a/Examples/FactoryExample/CreateExample.cs +++ b/Examples/FactoryExample/CreateExample.cs @@ -50,38 +50,41 @@ public static async Task CreateTwinsAsync(string adtEndpoint, CancellationToken //var client = GetDigitalTwinsClient(tenantId, clientId, clientSecret, adtEndpoint); var client = GetDigitalTwinsClient(adtEndpoint); - // Twin 1 - var factoryDtdl = serializer.SerializeTwin(factory); - var factoryDigitalTwin = JsonSerializer.Deserialize(factoryDtdl); - var factoryResponse = - await client.CreateOrReplaceDigitalTwinAsync(factory.FactoryId, - factoryDigitalTwin!, null, cancellationToken); - Console.WriteLine("CREATE TWIN SUCCESS: Id={0}, ETag={1}", factoryResponse.Value.Id, - factoryResponse.Value.ETag); - - // Twin 2 - var floor0Dtdl = serializer.SerializeTwin(factory.Floors[0]); - var floor0DigitalTwin = JsonSerializer.Deserialize(floor0Dtdl); - var floor0Response = - await client.CreateOrReplaceDigitalTwinAsync(factory.Floors[0].FloorId, - floor0DigitalTwin!, null, cancellationToken); - Console.WriteLine("CREATE TWIN SUCCESS: Id={0}, ETag={1}", floor0Response.Value.Id, - floor0Response.Value.ETag); - - // Relationship - var floor0Relationship = new BasicRelationship + await CreateTwinInstanceAsync(client, factory.FactoryId, serializer.SerializeTwin(factory), + cancellationToken); + + foreach (var floor in factory.Floors) { - Id = $"{factory.FactoryId}_{factory.Floors[0].FloorId}", - Name = "floors", - SourceId = factory.FactoryId, - TargetId = factory.Floors[0].FloorId - }; - var floor0RelationshipResponse = - await client.CreateOrReplaceRelationshipAsync(factory.FactoryId, floor0Relationship.Id, - floor0Relationship, null, cancellationToken); - Console.WriteLine("CREATE RELATIONSHIP SUCCESS: Id={0}, ETag={1}", - floor0RelationshipResponse.Value.Id, - floor0RelationshipResponse.Value.ETag); + 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) { @@ -89,6 +92,50 @@ await client.CreateOrReplaceRelationshipAsync(factory.FactoryId, floor0Relations } } + 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(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) { diff --git a/Examples/FactoryExample/Devices/ProductionStepFanning.cs b/Examples/FactoryExample/Devices/ProductionStepFanning.cs new file mode 100644 index 0000000..18a67ae --- /dev/null +++ b/Examples/FactoryExample/Devices/ProductionStepFanning.cs @@ -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; } + } +} diff --git a/Examples/FactoryExample/Devices/ProductionStepMoulding.cs b/Examples/FactoryExample/Devices/ProductionStepMoulding.cs new file mode 100644 index 0000000..7a0f2e1 --- /dev/null +++ b/Examples/FactoryExample/Devices/ProductionStepMoulding.cs @@ -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; } + } +} diff --git a/Examples/FactoryExample/Program.cs b/Examples/FactoryExample/Program.cs index 052992e..739be47 100644 --- a/Examples/FactoryExample/Program.cs +++ b/Examples/FactoryExample/Program.cs @@ -13,12 +13,23 @@ public static class Program public static readonly Type[] ModelTypes = { typeof(Factory), typeof(FactoryFloor), typeof(ProductionLine), typeof(ProductionStep), - typeof(ProductionStepGrinding) + typeof(ProductionStepGrinding), typeof(ProductionStepFanning), typeof(ProductionStepMoulding) }; public static Factory CreateFactoryTwin() { - var productionStepGrinding = new ProductionStepGrinding + var production1Step3Moulding = new ProductionStepMoulding + { + ChassisTemperature = 50, + FinalStep = true, + //OperationStatus = ProductionStepStatus.Online, + PowerUsage = 100, + StartTime = DateTimeOffset.UnixEpoch, + StepId = "line1.step3", + StepName = "Moulding Step" + }; + + var production1Step2Grinding = new ProductionStepGrinding { ChassisTemperature = 50, FinalStep = false, @@ -26,28 +37,44 @@ public static Factory CreateFactoryTwin() GrindingTime = 30, //OperationStatus = ProductionStepStatus.Online, PowerUsage = 100, - //StartTime = new DateTimeOffset(2021, 11, 17, 19, 57, 0, TimeSpan.FromHours(10)), - StepId = "step1", - StepName = "GrindingStep" + StartTime = DateTimeOffset.UnixEpoch, + StepId = "line1.step2", + StepName = "Grinding Step", + StepLink = production1Step3Moulding + }; + + var production1Step1Fanning = new ProductionStepFanning() + { + ChassisTemperature = 50, + FinalStep = false, + FanSpeed = 0.5, + //OperationStatus = ProductionStepStatus.Online, + PowerUsage = 100, + StartTime = DateTimeOffset.UnixEpoch, + StepId = "line1.step1", + StepName = "Fanning Step", + StepLink = production1Step2Grinding }; - var productionLine = new ProductionLine + var productionLine1 = new ProductionLine { - CurrentProductId = "production1", + CurrentProductId = "product5", LineId = "line1", - LineName = "ProductionLine", + LineName = "Production Line 1", //LineOperationStatus = ProductionLineStatus.Online, - ProductBatchNumber = 5 + ProductBatchNumber = 6 }; - productionLine.RunsSteps.Add(productionStepGrinding); + productionLine1.RunsSteps.Add(production1Step1Fanning); + productionLine1.RunsSteps.Add(production1Step2Grinding); + productionLine1.RunsSteps.Add(production1Step3Moulding); - var factoryFloor = new FactoryFloor + var factory1Floor1 = new FactoryFloor { - ComfortIndex = 0.8, FloorId = "floor1", FloorName = "FactoryFloor", Temperature = 23 + ComfortIndex = 0.8, FloorId = "factory1.floor1", FloorName = "Factory 1 Floor 1", Temperature = 23 }; - factoryFloor.RunsLines.Add(productionLine); + factory1Floor1.RunsLines.Add(productionLine1); - var factory = new Factory + var factory1 = new Factory { Country = "AU", FactoryId = "factory1", @@ -57,8 +84,8 @@ public static Factory CreateFactoryTwin() Tags = String.Empty, ZipCode = "4000" }; - factory.Floors.Add(factoryFloor); - return factory; + factory1.Floors.Add(factory1Floor1); + return factory1; } public static async Task Main(string[] args) From bbdce19e687030bf7e98bd2b2d5e1f60374013da Mon Sep 17 00:00:00 2001 From: Sly Gryphon Date: Sat, 18 Dec 2021 13:49:51 +1000 Subject: [PATCH 32/33] Add explorer pictures to readme --- Examples/FactoryExample/ReadMe.md | 4 ++++ .../images/model-graph-example.png | Bin 0 -> 121523 bytes .../images/twins-graph-example.png | Bin 0 -> 116734 bytes 3 files changed, 4 insertions(+) create mode 100644 Examples/FactoryExample/images/model-graph-example.png create mode 100644 Examples/FactoryExample/images/twins-graph-example.png diff --git a/Examples/FactoryExample/ReadMe.md b/Examples/FactoryExample/ReadMe.md index ed82747..38b717a 100644 --- a/Examples/FactoryExample/ReadMe.md +++ b/Examples/FactoryExample/ReadMe.md @@ -78,6 +78,8 @@ dotnet run -- --create model --endpoint "https://$hostName" After this, if you refresh the Models in Digital Twins Explorer, you will see the uploaded models. +![Explorer model graph](images/model-graph-example.png) + You then need to upload the Twin instances: ``` pwsh @@ -87,6 +89,8 @@ dotnet run -- --create twin --endpoint "https://$hostName" To see the Twin instances, ensure the query explorer has the default query `SELECT * FROM digitaltwins`, and then click Run Query. The twin instances should appear in the Twins list and Twin Graph. +![Explorer twins graph](images/twins-graph-example.png) + Cleanup ------- diff --git a/Examples/FactoryExample/images/model-graph-example.png b/Examples/FactoryExample/images/model-graph-example.png new file mode 100644 index 0000000000000000000000000000000000000000..a331fac1a7c7f1021fe795938ef22246f0d858ec GIT binary patch literal 121523 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

QlNE!Ki-+ITMU3v@a*xp-${7}YD3K>o*ud^ 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 literal 0 HcmV?d00001 diff --git a/Examples/FactoryExample/images/twins-graph-example.png b/Examples/FactoryExample/images/twins-graph-example.png new file mode 100644 index 0000000000000000000000000000000000000000..1ddae211d2c8adc2d8863a2214fee98b1f49b59d GIT binary patch literal 116734 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

  • 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

    azC7TlN(J* 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 literal 0 HcmV?d00001 From c39e73315946776422a85d9ae7b5a6c30d57e41a Mon Sep 17 00:00:00 2001 From: Sly Gryphon Date: Thu, 31 Mar 2022 09:14:12 +1000 Subject: [PATCH 33/33] Tweak to make example serializer show the concrete object properties --- Examples/FactoryExample/Program.cs | 2 +- Examples/FactoryExample/SerializeExample.cs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Examples/FactoryExample/Program.cs b/Examples/FactoryExample/Program.cs index 739be47..a9bffa2 100644 --- a/Examples/FactoryExample/Program.cs +++ b/Examples/FactoryExample/Program.cs @@ -145,7 +145,7 @@ public static async Task Main(string[] args) private static void ShowHelp() { Console.WriteLine(" --serialize model : shows serialized model examples"); - Console.WriteLine(" --serialize example : shows serialized twin examples"); + Console.WriteLine(" --serialize twin : shows serialized twin examples"); Console.WriteLine(" --parse model : parse and validate the example model"); Console.WriteLine(" --create model --endpoint : parse and upload the example model"); } diff --git a/Examples/FactoryExample/SerializeExample.cs b/Examples/FactoryExample/SerializeExample.cs index 4954e49..b9d6b72 100644 --- a/Examples/FactoryExample/SerializeExample.cs +++ b/Examples/FactoryExample/SerializeExample.cs @@ -1,4 +1,5 @@ using System; +using FactoryExample.Devices; using Telstra.Twins.Core; using Telstra.Twins.Services; @@ -30,7 +31,7 @@ public static void SerializeTwins() Console.WriteLine(twin1Dtdl); Console.WriteLine(); - var twin2Dtdl = serializer.SerializeTwin(factory.Floors[0].RunsLines[0].RunsSteps[0]); + var twin2Dtdl = serializer.SerializeTwin(factory.Floors[0].RunsLines[0].RunsSteps[0] as ProductionStepFanning); Console.WriteLine(twin2Dtdl); Console.WriteLine(); }