From 5ef31acf4a8051fb3d2fe31ac144c10b726fab3c Mon Sep 17 00:00:00 2001 From: Spyros Garyfallos Date: Thu, 10 May 2018 13:12:14 -0700 Subject: [PATCH] heavy refactoring abstracting modules --- Microsoft.Azure.IoT.TypeEdge.sln | 49 ++++- Microsoft.Azure.IoT.TypeEdge/Hubs/EdgeHub.cs | 9 - .../Microsoft.Azure.IoT.TypeEdge.csproj | 1 + Microsoft.Azure.IoT.TypeEdge/ModuleProxy.cs | 13 ++ .../Modules/EdgeMethodAttribute.cs | 8 + .../Modules/EdgeModule.cs | 6 +- .../Modules/EdgeModuleProxy.cs | 6 + .../Modules/Endpoint.cs | 2 +- .../Modules/MethodArgument.cs | 6 + .../Modules/MethodResult.cs | 8 + .../Modules/Output.cs | 1 - .../TypeEdgeApplication.cs | 192 ++++++++++-------- .../NormalizeTemperatureModule.cs | 35 ++++ .../NormalizeTemperatureModule.csproj | 12 ++ .../TemperatureModule.cs | 10 +- TemperatureModule/TemperatureModule.csproj | 12 ++ ThermostatApplication.EdgeHost/Program.cs | 30 +++ .../ThermostatApplication.EdgeHost.csproj | 26 +++ .../appsettings_thermostat.json | 2 +- .../Messages/TemperatureModuleInput.cs | 2 +- .../Messages/TemperatureModuleOutput.cs | 2 +- .../Modules/INormalizeTemperatureModule.cs | 10 + .../Modules/ITemperatureModule.cs | 14 ++ .../TemperatureScale.cs | 2 +- .../ThermostatApplication.Shared.csproj | 8 - .../Modules/NormalizeTemperatureModule.cs | 19 -- .../Options/NormalizeTemperatureOptions.cs | 9 - .../Options/ReadTemperatureOptions.cs | 9 - ThermpostatEdgeApplication/Program.cs | 25 --- .../ThermostatApplication.cs | 46 ----- 30 files changed, 344 insertions(+), 230 deletions(-) create mode 100644 Microsoft.Azure.IoT.TypeEdge/ModuleProxy.cs create mode 100644 Microsoft.Azure.IoT.TypeEdge/Modules/EdgeMethodAttribute.cs create mode 100644 Microsoft.Azure.IoT.TypeEdge/Modules/EdgeModuleProxy.cs create mode 100644 Microsoft.Azure.IoT.TypeEdge/Modules/MethodArgument.cs create mode 100644 Microsoft.Azure.IoT.TypeEdge/Modules/MethodResult.cs create mode 100644 NormalizeTemperatureModule/NormalizeTemperatureModule.cs create mode 100644 NormalizeTemperatureModule/NormalizeTemperatureModule.csproj rename {ThermpostatEdgeApplication/Modules => TemperatureModule}/TemperatureModule.cs (76%) create mode 100644 TemperatureModule/TemperatureModule.csproj create mode 100644 ThermostatApplication.EdgeHost/Program.cs create mode 100644 ThermostatApplication.EdgeHost/ThermostatApplication.EdgeHost.csproj rename {ThermpostatEdgeApplication => ThermostatApplication.EdgeHost}/appsettings_thermostat.json (84%) rename {ThermpostatEdgeApplication => ThermostatApplication.Shared}/Messages/TemperatureModuleInput.cs (94%) rename {ThermpostatEdgeApplication => ThermostatApplication.Shared}/Messages/TemperatureModuleOutput.cs (95%) create mode 100644 ThermostatApplication.Shared/Modules/INormalizeTemperatureModule.cs create mode 100644 ThermostatApplication.Shared/Modules/ITemperatureModule.cs rename {ThermpostatEdgeApplication => ThermostatApplication.Shared}/TemperatureScale.cs (66%) rename ThermpostatEdgeApplication/ThermpostatEdgeApplication.csproj => ThermostatApplication.Shared/ThermostatApplication.Shared.csproj (62%) delete mode 100644 ThermpostatEdgeApplication/Modules/NormalizeTemperatureModule.cs delete mode 100644 ThermpostatEdgeApplication/Options/NormalizeTemperatureOptions.cs delete mode 100644 ThermpostatEdgeApplication/Options/ReadTemperatureOptions.cs delete mode 100644 ThermpostatEdgeApplication/Program.cs delete mode 100644 ThermpostatEdgeApplication/ThermostatApplication.cs diff --git a/Microsoft.Azure.IoT.TypeEdge.sln b/Microsoft.Azure.IoT.TypeEdge.sln index e4fe5c7..afc1183 100644 --- a/Microsoft.Azure.IoT.TypeEdge.sln +++ b/Microsoft.Azure.IoT.TypeEdge.sln @@ -3,8 +3,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.27428.1 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThermpostatEdgeApplication", "ThermpostatEdgeApplication\ThermpostatEdgeApplication.csproj", "{6E41A1D9-FD4D-43BD-932A-D88459C7F4E5}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "hub", "hub", "{34DAEE1A-E6E8-4059-9142-BF0170F3EAA8}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Azure.Devices.Edge.Hub.Amqp", "..\..\..\internal\Azure-IoT-Edge-Core\edge-hub\src\Microsoft.Azure.Devices.Edge.Hub.Amqp\Microsoft.Azure.Devices.Edge.Hub.Amqp.csproj", "{123E0E0F-3CAC-4095-B008-848F32A59C38}" @@ -31,6 +29,18 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Azure.Devices.Edg EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Azure.IoT.TypeEdge", "Microsoft.Azure.IoT.TypeEdge\Microsoft.Azure.IoT.TypeEdge.csproj", "{54587D56-7C22-4084-9321-84D57C2F6ECB}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ThermostatApplication", "ThermostatApplication", "{2E4AF4B3-04D0-4950-979B-B04052B8E20A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThermostatApplication.EdgeHost", "ThermostatApplication.EdgeHost\ThermostatApplication.EdgeHost.csproj", "{2C06F377-0612-431F-BA91-A2F5A561E789}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThermostatApplication.Shared", "ThermostatApplication.Shared\ThermostatApplication.Shared.csproj", "{CB2C4940-747F-4C45-9EA8-4C98F7F3AD41}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Modules", "Modules", "{40D0EFBC-3D80-42C8-9623-B9CAD4B96EFF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TemperatureModule", "TemperatureModule\TemperatureModule.csproj", "{2B79BE65-8725-42FE-9F63-BC1797080E70}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NormalizeTemperatureModule", "NormalizeTemperatureModule\NormalizeTemperatureModule.csproj", "{A55A00B6-BABA-414D-A38F-C4CAB4B9331B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution CodeCoverage|Any CPU = CodeCoverage|Any CPU @@ -38,12 +48,6 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {6E41A1D9-FD4D-43BD-932A-D88459C7F4E5}.CodeCoverage|Any CPU.ActiveCfg = Release|Any CPU - {6E41A1D9-FD4D-43BD-932A-D88459C7F4E5}.CodeCoverage|Any CPU.Build.0 = Release|Any CPU - {6E41A1D9-FD4D-43BD-932A-D88459C7F4E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6E41A1D9-FD4D-43BD-932A-D88459C7F4E5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6E41A1D9-FD4D-43BD-932A-D88459C7F4E5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6E41A1D9-FD4D-43BD-932A-D88459C7F4E5}.Release|Any CPU.Build.0 = Release|Any CPU {123E0E0F-3CAC-4095-B008-848F32A59C38}.CodeCoverage|Any CPU.ActiveCfg = CodeCoverage|Any CPU {123E0E0F-3CAC-4095-B008-848F32A59C38}.CodeCoverage|Any CPU.Build.0 = CodeCoverage|Any CPU {123E0E0F-3CAC-4095-B008-848F32A59C38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU @@ -116,6 +120,30 @@ Global {54587D56-7C22-4084-9321-84D57C2F6ECB}.Debug|Any CPU.Build.0 = Debug|Any CPU {54587D56-7C22-4084-9321-84D57C2F6ECB}.Release|Any CPU.ActiveCfg = Release|Any CPU {54587D56-7C22-4084-9321-84D57C2F6ECB}.Release|Any CPU.Build.0 = Release|Any CPU + {2C06F377-0612-431F-BA91-A2F5A561E789}.CodeCoverage|Any CPU.ActiveCfg = Debug|Any CPU + {2C06F377-0612-431F-BA91-A2F5A561E789}.CodeCoverage|Any CPU.Build.0 = Debug|Any CPU + {2C06F377-0612-431F-BA91-A2F5A561E789}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2C06F377-0612-431F-BA91-A2F5A561E789}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2C06F377-0612-431F-BA91-A2F5A561E789}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2C06F377-0612-431F-BA91-A2F5A561E789}.Release|Any CPU.Build.0 = Release|Any CPU + {CB2C4940-747F-4C45-9EA8-4C98F7F3AD41}.CodeCoverage|Any CPU.ActiveCfg = Debug|Any CPU + {CB2C4940-747F-4C45-9EA8-4C98F7F3AD41}.CodeCoverage|Any CPU.Build.0 = Debug|Any CPU + {CB2C4940-747F-4C45-9EA8-4C98F7F3AD41}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CB2C4940-747F-4C45-9EA8-4C98F7F3AD41}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CB2C4940-747F-4C45-9EA8-4C98F7F3AD41}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CB2C4940-747F-4C45-9EA8-4C98F7F3AD41}.Release|Any CPU.Build.0 = Release|Any CPU + {2B79BE65-8725-42FE-9F63-BC1797080E70}.CodeCoverage|Any CPU.ActiveCfg = Debug|Any CPU + {2B79BE65-8725-42FE-9F63-BC1797080E70}.CodeCoverage|Any CPU.Build.0 = Debug|Any CPU + {2B79BE65-8725-42FE-9F63-BC1797080E70}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2B79BE65-8725-42FE-9F63-BC1797080E70}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2B79BE65-8725-42FE-9F63-BC1797080E70}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2B79BE65-8725-42FE-9F63-BC1797080E70}.Release|Any CPU.Build.0 = Release|Any CPU + {A55A00B6-BABA-414D-A38F-C4CAB4B9331B}.CodeCoverage|Any CPU.ActiveCfg = Debug|Any CPU + {A55A00B6-BABA-414D-A38F-C4CAB4B9331B}.CodeCoverage|Any CPU.Build.0 = Debug|Any CPU + {A55A00B6-BABA-414D-A38F-C4CAB4B9331B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A55A00B6-BABA-414D-A38F-C4CAB4B9331B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A55A00B6-BABA-414D-A38F-C4CAB4B9331B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A55A00B6-BABA-414D-A38F-C4CAB4B9331B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -132,6 +160,11 @@ Global {FADB4DA5-7927-4505-AE23-09481B221FED} = {34DAEE1A-E6E8-4059-9142-BF0170F3EAA8} {6AF2C7B5-C749-47B0-BDE7-55F57C70E961} = {34DAEE1A-E6E8-4059-9142-BF0170F3EAA8} {4765DE78-0E50-4F41-9603-8B598A56D4C4} = {34DAEE1A-E6E8-4059-9142-BF0170F3EAA8} + {2C06F377-0612-431F-BA91-A2F5A561E789} = {2E4AF4B3-04D0-4950-979B-B04052B8E20A} + {CB2C4940-747F-4C45-9EA8-4C98F7F3AD41} = {2E4AF4B3-04D0-4950-979B-B04052B8E20A} + {40D0EFBC-3D80-42C8-9623-B9CAD4B96EFF} = {2E4AF4B3-04D0-4950-979B-B04052B8E20A} + {2B79BE65-8725-42FE-9F63-BC1797080E70} = {40D0EFBC-3D80-42C8-9623-B9CAD4B96EFF} + {A55A00B6-BABA-414D-A38F-C4CAB4B9331B} = {40D0EFBC-3D80-42C8-9623-B9CAD4B96EFF} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {114E5850-267D-4B44-ACD5-91ACA382DDBC} diff --git a/Microsoft.Azure.IoT.TypeEdge/Hubs/EdgeHub.cs b/Microsoft.Azure.IoT.TypeEdge/Hubs/EdgeHub.cs index 21485c4..550a48e 100644 --- a/Microsoft.Azure.IoT.TypeEdge/Hubs/EdgeHub.cs +++ b/Microsoft.Azure.IoT.TypeEdge/Hubs/EdgeHub.cs @@ -10,16 +10,7 @@ namespace Microsoft.Azure.IoT.TypeEdge.Hubs { public class EdgeHub : EdgeModule { - public EdgeHub() - { - Upstream = new Upstream(this); - Downstream = new Downstream(this); - } public override string Name => Agent.Constants.EdgeHubModuleIdentityName; - - public Upstream Upstream { get; set; } - public Downstream Downstream { get; set; } - private IConfigurationRoot HubServiceConfiguration { get; set; } public override CreationResult Configure(IConfigurationRoot configuration) diff --git a/Microsoft.Azure.IoT.TypeEdge/Microsoft.Azure.IoT.TypeEdge.csproj b/Microsoft.Azure.IoT.TypeEdge/Microsoft.Azure.IoT.TypeEdge.csproj index efba141..1ea3bb8 100644 --- a/Microsoft.Azure.IoT.TypeEdge/Microsoft.Azure.IoT.TypeEdge.csproj +++ b/Microsoft.Azure.IoT.TypeEdge/Microsoft.Azure.IoT.TypeEdge.csproj @@ -9,6 +9,7 @@ + diff --git a/Microsoft.Azure.IoT.TypeEdge/ModuleProxy.cs b/Microsoft.Azure.IoT.TypeEdge/ModuleProxy.cs new file mode 100644 index 0000000..a682b88 --- /dev/null +++ b/Microsoft.Azure.IoT.TypeEdge/ModuleProxy.cs @@ -0,0 +1,13 @@ +using Castle.DynamicProxy; +using System.Dynamic; + +namespace Microsoft.Azure.IoT.TypeEdge +{ + internal class ModuleProxy: IInterceptor + { + public void Intercept(IInvocation invocation) + { + } + } + +} diff --git a/Microsoft.Azure.IoT.TypeEdge/Modules/EdgeMethodAttribute.cs b/Microsoft.Azure.IoT.TypeEdge/Modules/EdgeMethodAttribute.cs new file mode 100644 index 0000000..ce2fbc2 --- /dev/null +++ b/Microsoft.Azure.IoT.TypeEdge/Modules/EdgeMethodAttribute.cs @@ -0,0 +1,8 @@ +using System; + +namespace Microsoft.Azure.IoT.TypeEdge.Modules +{ + public class EdgeMethodAttribute : Attribute + { + } +} \ No newline at end of file diff --git a/Microsoft.Azure.IoT.TypeEdge/Modules/EdgeModule.cs b/Microsoft.Azure.IoT.TypeEdge/Modules/EdgeModule.cs index 1fc23df..461e2c6 100644 --- a/Microsoft.Azure.IoT.TypeEdge/Modules/EdgeModule.cs +++ b/Microsoft.Azure.IoT.TypeEdge/Modules/EdgeModule.cs @@ -29,11 +29,13 @@ namespace Microsoft.Azure.IoT.TypeEdge.Modules private ITransportSettings[] TransportSettings { get; set; } private Dictionary Subscriptions { get; set; } + public Upstream Upstream { get; set; } public EdgeModule() { Subscriptions = new Dictionary(); Routes = new List(); + Upstream = new Upstream(this); var props = GetType().GetProperties(); @@ -56,6 +58,9 @@ namespace Microsoft.Azure.IoT.TypeEdge.Modules } public virtual string Name { get { return this.GetType().Name; } } + public virtual void ConfigureSubscriptions() + { + } public virtual CreationResult Configure(IConfigurationRoot configuration) { return CreationResult.OK; @@ -155,7 +160,6 @@ namespace Microsoft.Azure.IoT.TypeEdge.Modules public Output DiagnosticsOutput { get; set; } - public void DependsOn(EdgeModule module) { } diff --git a/Microsoft.Azure.IoT.TypeEdge/Modules/EdgeModuleProxy.cs b/Microsoft.Azure.IoT.TypeEdge/Modules/EdgeModuleProxy.cs new file mode 100644 index 0000000..ae3aecf --- /dev/null +++ b/Microsoft.Azure.IoT.TypeEdge/Modules/EdgeModuleProxy.cs @@ -0,0 +1,6 @@ +namespace Microsoft.Azure.IoT.TypeEdge.Modules +{ + public class EdgeModuleProxy + { + } +} \ No newline at end of file diff --git a/Microsoft.Azure.IoT.TypeEdge/Modules/Endpoint.cs b/Microsoft.Azure.IoT.TypeEdge/Modules/Endpoint.cs index 0db073e..1cbcf89 100644 --- a/Microsoft.Azure.IoT.TypeEdge/Modules/Endpoint.cs +++ b/Microsoft.Azure.IoT.TypeEdge/Modules/Endpoint.cs @@ -7,7 +7,7 @@ namespace Microsoft.Azure.IoT.TypeEdge.Modules { public string Name { get; set; } public abstract string RouteName { get; } - public EdgeModule Module { get; set; } + internal EdgeModule Module { get; set; } public Endpoint(string name, EdgeModule module) { diff --git a/Microsoft.Azure.IoT.TypeEdge/Modules/MethodArgument.cs b/Microsoft.Azure.IoT.TypeEdge/Modules/MethodArgument.cs new file mode 100644 index 0000000..ba5e519 --- /dev/null +++ b/Microsoft.Azure.IoT.TypeEdge/Modules/MethodArgument.cs @@ -0,0 +1,6 @@ +namespace Microsoft.Azure.IoT.TypeEdge.Modules +{ + public class MethodArgument + { + } +} \ No newline at end of file diff --git a/Microsoft.Azure.IoT.TypeEdge/Modules/MethodResult.cs b/Microsoft.Azure.IoT.TypeEdge/Modules/MethodResult.cs new file mode 100644 index 0000000..8dd783a --- /dev/null +++ b/Microsoft.Azure.IoT.TypeEdge/Modules/MethodResult.cs @@ -0,0 +1,8 @@ +namespace Microsoft.Azure.IoT.TypeEdge.Modules +{ + public enum MethodResult + { + OK, + Error + } +} \ No newline at end of file diff --git a/Microsoft.Azure.IoT.TypeEdge/Modules/Output.cs b/Microsoft.Azure.IoT.TypeEdge/Modules/Output.cs index 08e5f1a..e03ef89 100644 --- a/Microsoft.Azure.IoT.TypeEdge/Modules/Output.cs +++ b/Microsoft.Azure.IoT.TypeEdge/Modules/Output.cs @@ -12,7 +12,6 @@ namespace Microsoft.Azure.IoT.TypeEdge.Modules } public override string RouteName => $"/messages/modules/{this.Module.Name}/outputs/{Name}"; - public string ModuleName { get { return Module.Name; } } public async Task PublishAsync(T message) { diff --git a/Microsoft.Azure.IoT.TypeEdge/TypeEdgeApplication.cs b/Microsoft.Azure.IoT.TypeEdge/TypeEdgeApplication.cs index 5cf0aea..0e608c9 100644 --- a/Microsoft.Azure.IoT.TypeEdge/TypeEdgeApplication.cs +++ b/Microsoft.Azure.IoT.TypeEdge/TypeEdgeApplication.cs @@ -19,65 +19,91 @@ using Microsoft.Azure.Devices.Common.Exceptions; using Newtonsoft.Json; using Microsoft.Azure.Devices.Shared; using Newtonsoft.Json.Linq; +using System.Linq; +using Autofac.Extras.DynamicProxy; +using Castle.DynamicProxy; namespace Microsoft.Azure.IoT.TypeEdge { - public abstract class TypeEdgeApplication + public class TypeEdgeApplication { - public IConfigurationRoot Configuration { get; } - public IContainer Container { get; private set; } + IConfigurationRoot configuration; + IContainer container; + ContainerBuilder containerBuilder; + ModuleCollection modules; + EdgeHub hub; + + public void RegisterModule<_IModule, _TModule>() + where _IModule : class + where _TModule : class + { + //containerBuilder.RegisterType<_TModule>(); + //containerBuilder.RegisterInstance(new ProxyGenerator().CreateInterfaceProxyWithoutTarget<_IModule>(new ModuleProxy()) as _IModule); + containerBuilder.RegisterType<_TModule>().AsSelf().As<_IModule>(); + } - public EdgeHub Hub { get; set; } - public ModuleCollection Modules { get; private set; } public TypeEdgeApplication(IConfigurationRoot configuration) { - Configuration = configuration; + this.configuration = configuration; + this.containerBuilder = new ContainerBuilder(); + hub = new EdgeHub(); - // add the framework services - var services = new ServiceCollection().AddLogging(); + } + public void Build() + { + //read the configuration first + var (iotHubConnectionString, deviceId) = ReadConfiguration(); - Modules = new ModuleCollection(); + //setup the container + BuildContainer(); - Hub = new EdgeHub(); + this.modules = CreateModules(); - Compose(); + var deviceSasKey = ProvisionDeviceAsync(iotHubConnectionString, deviceId, this.modules).Result; - Container = BuildContainer(services); + ConfigureModules(iotHubConnectionString, deviceId); + + BuildHub(iotHubConnectionString, deviceId, deviceSasKey); } - IContainer BuildContainer(IServiceCollection services) + #region Build + private void BuildContainer() { - var builder = new ContainerBuilder(); - builder.Populate(services); - builder.RegisterBuildCallback(c => { }); + var services = new ServiceCollection().AddLogging(); + containerBuilder.Populate(services); + containerBuilder.RegisterBuildCallback(c => { }); - var iotHubConnectionString = Configuration.GetValue(Agent.Constants.IotHubConnectionStringKey); + container = containerBuilder.Build(); + } + + private (string iotHubConnectionString, string deviceId) ReadConfiguration() + { + var iotHubConnectionString = configuration.GetValue(Agent.Constants.IotHubConnectionStringKey); if (String.IsNullOrEmpty(iotHubConnectionString)) throw new Exception($"Missing {Agent.Constants.IotHubConnectionStringKey} value in configuration"); - var deviceId = Configuration.GetValue("DeviceId"); + var deviceId = configuration.GetValue("DeviceId"); if (String.IsNullOrEmpty(deviceId)) throw new Exception($"Missing DeviceId value in configuration"); - #region edge hub config + return (iotHubConnectionString, deviceId); + } - //configure the edge hub + private void BuildHub(string iotHubConnectionString, string deviceId, string deviceSasKey) + { + //Calculate the Hub Enviroment Varialbes + var currentLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + Environment.SetEnvironmentVariable(HubService.Constants.SslCertEnvName, + "edge-hub-server.cert.pfx"); + Environment.SetEnvironmentVariable(HubService.Constants.SslCertPathEnvName, + Path.Combine(currentLocation, @"Certificates\edge-hub-server\cert\")); - Environment.SetEnvironmentVariable(HubService.Constants.SslCertEnvName, "edge-hub-server.cert.pfx"); - Environment.SetEnvironmentVariable(HubService.Constants.SslCertPathEnvName, Path.Combine( - Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), - @"Certificates\edge-hub-server\cert\")); - - Environment.SetEnvironmentVariable("EdgeModuleHubServerCAChainCertificateFile", Path.Combine( - Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), - @"Certificates\edge-chain-ca\cert\edge-chain-ca.cert.pem")); - - var storageFolder = Path.Combine( - Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), - @"Storage"); + Environment.SetEnvironmentVariable("EdgeModuleHubServerCAChainCertificateFile", + Path.Combine(currentLocation, @"Certificates\edge-chain-ca\cert\edge-chain-ca.cert.pem")); + var storageFolder = Path.Combine(currentLocation, @"Storage"); var hubStorageFolder = Path.Combine(storageFolder, HubService.Constants.EdgeHubStorageFolder); @@ -85,23 +111,6 @@ namespace Microsoft.Azure.IoT.TypeEdge Directory.CreateDirectory(hubStorageFolder); Environment.SetEnvironmentVariable("storageFolder", storageFolder); - #endregion - - - var deviceSasKey = ProvisionDeviceAsync(iotHubConnectionString, deviceId, Modules).Result; - - foreach (var module in Modules) - { - var moduleConnectionString = GetModuleConnectionStringAsync(iotHubConnectionString, deviceId, module.Name).Result; - - Environment.SetEnvironmentVariable(Agent.Constants.EdgeHubConnectionStringKey, moduleConnectionString); - - var moduleConfiguration = new ConfigurationBuilder() - .AddEnvironmentVariables() - .Build(); - - module.InternalConfigure(moduleConfiguration); - } var csBuilder = IotHubConnectionStringBuilder.Create(iotHubConnectionString); var edgeConnectionString = new Agent.ModuleConnectionString.ModuleConnectionStringBuilder(csBuilder.HostName, deviceId) @@ -116,12 +125,43 @@ namespace Microsoft.Azure.IoT.TypeEdge .AddEnvironmentVariables() .Build(); - Hub.InternalConfigure(edgeHubConfiguration); - - - IContainer container = builder.Build(); - return container; + hub.InternalConfigure(edgeHubConfiguration); } + + private void ConfigureModules(string iotHubConnectionString, string deviceId) + { + foreach (var module in this.modules) + { + var moduleConnectionString = GetModuleConnectionStringAsync(iotHubConnectionString, deviceId, module.Name).Result; + + Environment.SetEnvironmentVariable(Agent.Constants.EdgeHubConnectionStringKey, moduleConnectionString); + + var moduleConfiguration = new ConfigurationBuilder() + .AddEnvironmentVariables() + .Build(); + + module.InternalConfigure(moduleConfiguration); + } + } + + private ModuleCollection CreateModules() + { + var modules = new ModuleCollection(); + using (var scope = container.BeginLifetimeScope()) + { + foreach (var moduleType in container.ComponentRegistry.Registrations.Where(r => typeof(EdgeModule).IsAssignableFrom(r.Activator.LimitType)).Select(r => r.Activator.LimitType).Distinct()) + { + var module = scope.Resolve(moduleType) as EdgeModule; + + module.ConfigureSubscriptions(); + modules.Add(module); + } + } + + return modules; + } + + private async Task ProvisionDeviceAsync(string iotHubConnectionString, string deviceId, ModuleCollection modules) { var csBuilder = IotHubConnectionStringBuilder.Create(iotHubConnectionString); @@ -157,19 +197,26 @@ namespace Microsoft.Azure.IoT.TypeEdge createOptions = $" -e __MODULE_NAME='{module.Name}' " } })); - } + try + { + await registryManager.AddModuleAsync(new Devices.Module(deviceId, module.Name)); + } + catch (ModuleAlreadyExistsException) + { + } + } var twinContent = new TwinContent(); config.ModuleContent["$edgeHub"] = twinContent; var routes = new Dictionary(); - foreach (var route in Hub.Routes) + foreach (var route in hub.Routes) { routes[$"route{routes.Count}"] = route; } - foreach (var module in Modules) + foreach (var module in this.modules) { foreach (var route in module.Routes) { @@ -219,43 +266,18 @@ namespace Microsoft.Azure.IoT.TypeEdge .WithSharedAccessKey(sasKey) .Build(); } - - //private async Task ProvisionModuleAsync(string iotHubConnectionString, string deviceId, string moduleName) - //{ - // var csBuilder = IotHubConnectionStringBuilder.Create(iotHubConnectionString); - // RegistryManager registryManager = RegistryManager.CreateFromConnectionString(iotHubConnectionString); - // string sasKey = null; - // try - // { - // var module = await registryManager.AddModuleAsync(new Devices.Module(deviceId, moduleName)); - // sasKey = module.Authentication.SymmetricKey.PrimaryKey; - // } - // catch (ModuleAlreadyExistsException) - // { - // var module = await registryManager.GetModuleAsync(deviceId, moduleName); - // sasKey = module.Authentication.SymmetricKey.PrimaryKey; - // } - // return new Agent.ModuleConnectionString.ModuleConnectionStringBuilder(csBuilder.IotHubName, deviceId) - // .WithGatewayHostName(Environment.MachineName) - // .WithModuleId(moduleName) - // .WithSharedAccessKey(sasKey) - // .Build(); - //} - public abstract CompositionResult Compose(); + #endregion public async Task RunAsync() { List tasks = new List(); - tasks.Add(Hub.RunAsync()); + tasks.Add(hub.RunAsync()); //start all modules - foreach (var module in Modules) - { + foreach (var module in modules) tasks.Add(module.InternalRunAsync()); - } await Task.WhenAll(tasks.ToArray()); } - } } diff --git a/NormalizeTemperatureModule/NormalizeTemperatureModule.cs b/NormalizeTemperatureModule/NormalizeTemperatureModule.cs new file mode 100644 index 0000000..2bfc2f5 --- /dev/null +++ b/NormalizeTemperatureModule/NormalizeTemperatureModule.cs @@ -0,0 +1,35 @@ +using Microsoft.Azure.IoT.TypeEdge.Modules; +using ThermostatApplication; +using ThermostatApplication.Messages; +using ThermostatApplication.Modules; + +namespace Modules +{ + public class NormalizeTemperatureModule : EdgeModule, INormalizeTemperatureModule + { + ITemperatureModule temperatureModuleProxy; + + public Input Temperature { get; set; } + public Output NormalizedTemperature { get; set; } + + public NormalizeTemperatureModule(ITemperatureModule proxy) + { + temperatureModuleProxy = proxy; + } + + public override void ConfigureSubscriptions() { + + Temperature.Subscribe(temperatureModuleProxy.Temperature, async (temp) => + { + if (temp.Scale == TemperatureScale.Celsius) + temp.Temperature = temp.Temperature * 9 / 5 + 32; + + await NormalizedTemperature.PublishAsync(temp); + + return MessageResult.OK; + }); + + Upstream.Subscribe(NormalizedTemperature); + } + } +} diff --git a/NormalizeTemperatureModule/NormalizeTemperatureModule.csproj b/NormalizeTemperatureModule/NormalizeTemperatureModule.csproj new file mode 100644 index 0000000..3dc2057 --- /dev/null +++ b/NormalizeTemperatureModule/NormalizeTemperatureModule.csproj @@ -0,0 +1,12 @@ + + + + netcoreapp2.1 + + + + + + + + diff --git a/ThermpostatEdgeApplication/Modules/TemperatureModule.cs b/TemperatureModule/TemperatureModule.cs similarity index 76% rename from ThermpostatEdgeApplication/Modules/TemperatureModule.cs rename to TemperatureModule/TemperatureModule.cs index 41d46cc..06d9784 100644 --- a/ThermpostatEdgeApplication/Modules/TemperatureModule.cs +++ b/TemperatureModule/TemperatureModule.cs @@ -1,15 +1,15 @@ using Microsoft.Azure.IoT.TypeEdge; using Microsoft.Azure.IoT.TypeEdge.Modules; -using Microsoft.Extensions.Configuration; using System; -using System.Collections.Generic; -using System.Text; using System.Threading; using System.Threading.Tasks; +using ThermostatApplication; +using ThermostatApplication.Messages; +using ThermostatApplication.Modules; -namespace ThermpostatEdgeApplication.Modules +namespace Modules { - public class TemperatureModule : EdgeModule + public class TemperatureModule : EdgeModule, ITemperatureModule { public Output Temperature { get; set; } diff --git a/TemperatureModule/TemperatureModule.csproj b/TemperatureModule/TemperatureModule.csproj new file mode 100644 index 0000000..3dc2057 --- /dev/null +++ b/TemperatureModule/TemperatureModule.csproj @@ -0,0 +1,12 @@ + + + + netcoreapp2.1 + + + + + + + + diff --git a/ThermostatApplication.EdgeHost/Program.cs b/ThermostatApplication.EdgeHost/Program.cs new file mode 100644 index 0000000..0f9e428 --- /dev/null +++ b/ThermostatApplication.EdgeHost/Program.cs @@ -0,0 +1,30 @@ +using Microsoft.Azure.IoT.TypeEdge; +using Microsoft.Extensions.Configuration; +using Modules; +using System; +using System.Threading.Tasks; +using ThermostatApplication.Modules; + +namespace ThermostatApplication.EdgeHost +{ + class Program + { + static async Task Main(string[] args) + { + var configuration = new ConfigurationBuilder() + .AddJsonFile("appsettings_thermostat.json") + .Build(); + + var edgeApp = new TypeEdgeApplication(configuration); + + edgeApp.RegisterModule(); + edgeApp.RegisterModule(); + edgeApp.Build(); + + await edgeApp.RunAsync(); + + Console.WriteLine("Press to exit.."); + Console.ReadLine(); + } + } +} diff --git a/ThermostatApplication.EdgeHost/ThermostatApplication.EdgeHost.csproj b/ThermostatApplication.EdgeHost/ThermostatApplication.EdgeHost.csproj new file mode 100644 index 0000000..9cfc337 --- /dev/null +++ b/ThermostatApplication.EdgeHost/ThermostatApplication.EdgeHost.csproj @@ -0,0 +1,26 @@ + + + + Exe + netcoreapp2.1 + latest + + + + + + + + + + + + + + + + Always + + + + diff --git a/ThermpostatEdgeApplication/appsettings_thermostat.json b/ThermostatApplication.EdgeHost/appsettings_thermostat.json similarity index 84% rename from ThermpostatEdgeApplication/appsettings_thermostat.json rename to ThermostatApplication.EdgeHost/appsettings_thermostat.json index 3a03c3d..23f8cfc 100644 --- a/ThermpostatEdgeApplication/appsettings_thermostat.json +++ b/ThermostatApplication.EdgeHost/appsettings_thermostat.json @@ -2,6 +2,6 @@ "appSettings": { }, "iotHubConnectionString": "HostName=iotedgedev-iothub-7389d7.azure-devices.net;SharedAccessKeyName=iothubowner;SharedAccessKey=68K3zvI8CKbN7NM5s46N9rlP+zvPHPJKg7shy1rwMRU=", - "deviceId": "iotedgedev-edgedevice-new", + "deviceId": "type-edge-dev-device", "RuntimeLogLevel": "info" } diff --git a/ThermpostatEdgeApplication/Messages/TemperatureModuleInput.cs b/ThermostatApplication.Shared/Messages/TemperatureModuleInput.cs similarity index 94% rename from ThermpostatEdgeApplication/Messages/TemperatureModuleInput.cs rename to ThermostatApplication.Shared/Messages/TemperatureModuleInput.cs index c648f5d..7e6a1df 100644 --- a/ThermpostatEdgeApplication/Messages/TemperatureModuleInput.cs +++ b/ThermostatApplication.Shared/Messages/TemperatureModuleInput.cs @@ -5,7 +5,7 @@ using Microsoft.Azure.IoT.TypeEdge.Hubs; using Microsoft.Azure.IoT.TypeEdge.Modules; using Newtonsoft.Json; -namespace ThermpostatEdgeApplication +namespace ThermostatApplication.Messages { public class TemperatureModuleInput : IEdgeMessage { diff --git a/ThermpostatEdgeApplication/Messages/TemperatureModuleOutput.cs b/ThermostatApplication.Shared/Messages/TemperatureModuleOutput.cs similarity index 95% rename from ThermpostatEdgeApplication/Messages/TemperatureModuleOutput.cs rename to ThermostatApplication.Shared/Messages/TemperatureModuleOutput.cs index 346a991..b9ff399 100644 --- a/ThermpostatEdgeApplication/Messages/TemperatureModuleOutput.cs +++ b/ThermostatApplication.Shared/Messages/TemperatureModuleOutput.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; using System.Text; using System.Threading.Tasks; -namespace ThermpostatEdgeApplication +namespace ThermostatApplication.Messages { public class TemperatureModuleOutput : IEdgeMessage { diff --git a/ThermostatApplication.Shared/Modules/INormalizeTemperatureModule.cs b/ThermostatApplication.Shared/Modules/INormalizeTemperatureModule.cs new file mode 100644 index 0000000..23e7014 --- /dev/null +++ b/ThermostatApplication.Shared/Modules/INormalizeTemperatureModule.cs @@ -0,0 +1,10 @@ +using Microsoft.Azure.IoT.TypeEdge.Modules; +using ThermostatApplication.Messages; + +namespace ThermostatApplication.Modules +{ + public interface INormalizeTemperatureModule + { + Output NormalizedTemperature { get; set; } + } +} \ No newline at end of file diff --git a/ThermostatApplication.Shared/Modules/ITemperatureModule.cs b/ThermostatApplication.Shared/Modules/ITemperatureModule.cs new file mode 100644 index 0000000..00e1ba4 --- /dev/null +++ b/ThermostatApplication.Shared/Modules/ITemperatureModule.cs @@ -0,0 +1,14 @@ +using System; +using System.Threading.Tasks; +using Microsoft.Azure.IoT.TypeEdge; +using Microsoft.Azure.IoT.TypeEdge.Hubs; +using Microsoft.Azure.IoT.TypeEdge.Modules; +using ThermostatApplication.Messages; + +namespace ThermostatApplication.Modules +{ + public interface ITemperatureModule + { + Output Temperature { get; set; } + } +} \ No newline at end of file diff --git a/ThermpostatEdgeApplication/TemperatureScale.cs b/ThermostatApplication.Shared/TemperatureScale.cs similarity index 66% rename from ThermpostatEdgeApplication/TemperatureScale.cs rename to ThermostatApplication.Shared/TemperatureScale.cs index 9d35585..9d27740 100644 --- a/ThermpostatEdgeApplication/TemperatureScale.cs +++ b/ThermostatApplication.Shared/TemperatureScale.cs @@ -1,4 +1,4 @@ -namespace ThermpostatEdgeApplication +namespace ThermostatApplication { public enum TemperatureScale { diff --git a/ThermpostatEdgeApplication/ThermpostatEdgeApplication.csproj b/ThermostatApplication.Shared/ThermostatApplication.Shared.csproj similarity index 62% rename from ThermpostatEdgeApplication/ThermpostatEdgeApplication.csproj rename to ThermostatApplication.Shared/ThermostatApplication.Shared.csproj index a56d700..09df76b 100644 --- a/ThermpostatEdgeApplication/ThermpostatEdgeApplication.csproj +++ b/ThermostatApplication.Shared/ThermostatApplication.Shared.csproj @@ -1,9 +1,7 @@ - Exe netcoreapp2.1 - latest @@ -14,10 +12,4 @@ - - - Always - - - diff --git a/ThermpostatEdgeApplication/Modules/NormalizeTemperatureModule.cs b/ThermpostatEdgeApplication/Modules/NormalizeTemperatureModule.cs deleted file mode 100644 index 7bc109a..0000000 --- a/ThermpostatEdgeApplication/Modules/NormalizeTemperatureModule.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Autofac; -using Microsoft.Azure.IoT.TypeEdge; -using Microsoft.Azure.IoT.TypeEdge.Modules; -using Microsoft.Extensions.Configuration; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace ThermpostatEdgeApplication.Modules -{ - public class NormalizeTemperatureModule : EdgeModule - { - - public Input Temperature { get; set; } - public Output NormalizedTemperature { get; set; } - } -} diff --git a/ThermpostatEdgeApplication/Options/NormalizeTemperatureOptions.cs b/ThermpostatEdgeApplication/Options/NormalizeTemperatureOptions.cs deleted file mode 100644 index f68867f..0000000 --- a/ThermpostatEdgeApplication/Options/NormalizeTemperatureOptions.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Microsoft.Azure.IoT.TypeEdge.Modules; - -namespace ThermpostatEdgeApplication -{ - public class NormalizeTemperatureOptions : IModuleOptions - { - public string DeviceConnectionString { get; set; } - } -} \ No newline at end of file diff --git a/ThermpostatEdgeApplication/Options/ReadTemperatureOptions.cs b/ThermpostatEdgeApplication/Options/ReadTemperatureOptions.cs deleted file mode 100644 index 51ba495..0000000 --- a/ThermpostatEdgeApplication/Options/ReadTemperatureOptions.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Microsoft.Azure.IoT.TypeEdge.Modules; - -namespace ThermpostatEdgeApplication -{ - public class ReadTemperatureOptions : IModuleOptions - { - public string DeviceConnectionString { get; set; } - } -} \ No newline at end of file diff --git a/ThermpostatEdgeApplication/Program.cs b/ThermpostatEdgeApplication/Program.cs deleted file mode 100644 index 3004f01..0000000 --- a/ThermpostatEdgeApplication/Program.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Microsoft.Extensions.Configuration; -using System; -using System.IO; -using System.Threading.Tasks; - -namespace ThermpostatEdgeApplication -{ - class Program - { - static async Task Main(string[] args) - { - var configuration = new ConfigurationBuilder() - .AddJsonFile("appsettings_thermostat.json") - .AddEnvironmentVariables() - .Build(); - - var edgeApp = new ThermostatApplication(configuration); - - await edgeApp.RunAsync(); - - Console.WriteLine("Press to exit.."); - Console.ReadLine(); - } - } -} diff --git a/ThermpostatEdgeApplication/ThermostatApplication.cs b/ThermpostatEdgeApplication/ThermostatApplication.cs deleted file mode 100644 index 347c0ed..0000000 --- a/ThermpostatEdgeApplication/ThermostatApplication.cs +++ /dev/null @@ -1,46 +0,0 @@ -using Microsoft.Azure.IoT.TypeEdge; -using Microsoft.Azure.IoT.TypeEdge.Hubs; -using Microsoft.Azure.IoT.TypeEdge.Modules; -using Microsoft.Extensions.Configuration; -using ThermpostatEdgeApplication.Modules; - -namespace ThermpostatEdgeApplication -{ - public class ThermostatApplication : TypeEdgeApplication - { - public ThermostatApplication(IConfigurationRoot configuration) - : base(configuration) - { - } - - public override CompositionResult Compose() - { - //setup modules - var temperatureModule = new TemperatureModule(); - var normalizeTemperatureModule = new NormalizeTemperatureModule(); - - Modules.Add(temperatureModule); - Modules.Add(normalizeTemperatureModule); - - //setup the modules pub/sub - temperatureModule.DefaultInput.Subscribe(Hub.Downstream, async (msg) => { return MessageResult.OK; }); - - normalizeTemperatureModule.Temperature.Subscribe(temperatureModule.Temperature, async (temp) => - { - if (temp.Scale == TemperatureScale.Celsius) - temp.Temperature = temp.Temperature * 9 / 5 + 32; - - await normalizeTemperatureModule.NormalizedTemperature.PublishAsync(temp); - - return MessageResult.OK; - }); - - Hub.Upstream.Subscribe(normalizeTemperatureModule.NormalizedTemperature); - - //setup module startup depedencies - normalizeTemperatureModule.DependsOn(temperatureModule); - - return CompositionResult.OK; - } - } -}