From a557d44c983eec2a6a892e403ae82d62b8275e83 Mon Sep 17 00:00:00 2001 From: Denis-Cosmin Nutiu Date: Sun, 10 Nov 2019 14:38:40 +0200 Subject: [PATCH] Add gRPC support for NucuCar.Sensors project --- .../EnvironmentSensor/Measurement.cs | 6 +-- NucuCar.Sensors/EnvironmentSensor/Sensor.cs | 54 ++++++++++++------- NucuCar.Sensors/EnvironmentSensor/Service.cs | 27 ++++++++++ NucuCar.Sensors/EnvironmentSensor/Worker.cs | 5 +- NucuCar.Sensors/GrpcStartup.cs | 43 +++++++++++++++ NucuCar.Sensors/NucuCar.Sensors.csproj | 29 ++++++++++ NucuCar.Sensors/Program.cs | 6 ++- .../Protos/EnvironmentSensor.proto | 19 +++++++ NucuCar.Sensors/Readme.md | 2 + NucuCar.Sensors/SensorState.cs | 1 + NucuCar.Sensors/appsettings.Development.json | 1 + NucuCar.Sensors/appsettings.json | 13 ++++- NucuCar.TestClient/NucuCar.TestClient.csproj | 17 ++++++ NucuCar.TestClient/Program.cs | 38 +++++++++++++ NucuCar.sln | 6 +++ 15 files changed, 240 insertions(+), 27 deletions(-) create mode 100644 NucuCar.Sensors/EnvironmentSensor/Service.cs create mode 100644 NucuCar.Sensors/GrpcStartup.cs create mode 100644 NucuCar.Sensors/Protos/EnvironmentSensor.proto create mode 100644 NucuCar.TestClient/NucuCar.TestClient.csproj create mode 100644 NucuCar.TestClient/Program.cs diff --git a/NucuCar.Sensors/EnvironmentSensor/Measurement.cs b/NucuCar.Sensors/EnvironmentSensor/Measurement.cs index 69f0313..17910a3 100644 --- a/NucuCar.Sensors/EnvironmentSensor/Measurement.cs +++ b/NucuCar.Sensors/EnvironmentSensor/Measurement.cs @@ -4,9 +4,9 @@ namespace NucuCar.Sensors.EnvironmentSensor { public struct Measurement { - public Temperature Temperature { get; set; } - public double Pressure { get; set; } - public double Humidity { get; set; } + public Temperature Temperature { get; private set; } + public double Pressure { get; private set; } + public double Humidity { get; private set; } public Measurement(Temperature temperature, double pressure, double humidity) : this() { diff --git a/NucuCar.Sensors/EnvironmentSensor/Sensor.cs b/NucuCar.Sensors/EnvironmentSensor/Sensor.cs index acb7e1a..e9a2f73 100644 --- a/NucuCar.Sensors/EnvironmentSensor/Sensor.cs +++ b/NucuCar.Sensors/EnvironmentSensor/Sensor.cs @@ -9,21 +9,52 @@ namespace NucuCar.Sensors.EnvironmentSensor { public class Sensor : IDisposable { - private readonly ILogger _logger; + private ILogger _logger; private I2cConnectionSettings _i2CSettings; private I2cDevice _i2CDevice; private Bme680 _bme680; private Measurement _measurement; private SensorState _sensorState; - public Sensor(ILogger logger) + /* Singleton Instance */ + public static Sensor Instance { get; } = new Sensor(); + + static Sensor() + { + } + + private Sensor() + { + _sensorState = SensorState.Uninitialized; + } + + public Measurement GetMeasurement() + { + return _measurement; + } + + public SensorState GetState() + { + return _sensorState; + } + + public void Dispose() + { + _bme680?.Dispose(); + } + + internal void SetLogger(ILogger logger) { _logger = logger; - InitializeSensor(); } internal void InitializeSensor() { + if (_sensorState == SensorState.Initialized) + { + return; + } + try { /* Connect to default i2c address 0x76 */ @@ -70,22 +101,5 @@ namespace NucuCar.Sensors.EnvironmentSensor _logger.LogInformation( $"{temperature.Celsius:N2} \u00B0C | {pressure} hPa | {humidity:N2} %rH"); } - - // TODO: Make gRpc accessible. - public Measurement GetMeasurement() - { - return _measurement; - } - - // TODO: Make gRpc accessible. - public SensorState GetState() - { - return _sensorState; - } - - public void Dispose() - { - _bme680?.Dispose(); - } } } \ No newline at end of file diff --git a/NucuCar.Sensors/EnvironmentSensor/Service.cs b/NucuCar.Sensors/EnvironmentSensor/Service.cs new file mode 100644 index 0000000..dad41e8 --- /dev/null +++ b/NucuCar.Sensors/EnvironmentSensor/Service.cs @@ -0,0 +1,27 @@ +using System.Threading.Tasks; +using Grpc.Core; +using Microsoft.Extensions.Logging; +using NucuCarGrpcSensors; + +namespace NucuCar.Sensors.EnvironmentSensor +{ + public class Service : EnvironmentSensorGrpcService.EnvironmentSensorGrpcServiceBase + { + private readonly ILogger _logger; + private readonly Sensor _sensor; + + public Service(ILogger logger) + { + _sensor = Sensor.Instance; + _logger = logger; + } + + public override Task SayHello(HelloRequest request, ServerCallContext context) + { + return Task.FromResult(new HelloReply + { + Message = "Hello " + request.Name + }); + } + } +} \ No newline at end of file diff --git a/NucuCar.Sensors/EnvironmentSensor/Worker.cs b/NucuCar.Sensors/EnvironmentSensor/Worker.cs index fe5fcb9..a785250 100644 --- a/NucuCar.Sensors/EnvironmentSensor/Worker.cs +++ b/NucuCar.Sensors/EnvironmentSensor/Worker.cs @@ -17,7 +17,10 @@ namespace NucuCar.Sensors.EnvironmentSensor protected override async Task ExecuteAsync(CancellationToken stoppingToken) { - using var sensor = new Sensor(_logger); + using var sensor = Sensor.Instance; + sensor.SetLogger(_logger); + sensor.InitializeSensor(); + while (!stoppingToken.IsCancellationRequested) { if (sensor.GetState() == SensorState.Initialized) diff --git a/NucuCar.Sensors/GrpcStartup.cs b/NucuCar.Sensors/GrpcStartup.cs new file mode 100644 index 0000000..e09b7ea --- /dev/null +++ b/NucuCar.Sensors/GrpcStartup.cs @@ -0,0 +1,43 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; + +namespace NucuCar.Sensors +{ + public class GrpcStartup + { + // This method gets called by the runtime. Use this method to add services to the container. + // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 + public void ConfigureServices(IServiceCollection services) + { + services.AddGrpc(); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + + app.UseRouting(); + app.UseHttpsRedirection(); + + app.UseEndpoints(endpoints => + { + endpoints.MapGrpcService(); + + endpoints.MapGet("/", + async context => + { + await context.Response.WriteAsync( + "Communication with gRPC endpoints must be made through a gRPC client. " + + "To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909"); + }); + }); + } + } +} \ No newline at end of file diff --git a/NucuCar.Sensors/NucuCar.Sensors.csproj b/NucuCar.Sensors/NucuCar.Sensors.csproj index f7c379f..88178c4 100644 --- a/NucuCar.Sensors/NucuCar.Sensors.csproj +++ b/NucuCar.Sensors/NucuCar.Sensors.csproj @@ -6,6 +6,10 @@ + + + + @@ -13,37 +17,62 @@ <_UnmanagedRegistrationCache Remove="obj\NucuCar.Sensors.csproj.UnmanagedRegistration.cache" /> + <_UnmanagedRegistrationCache Remove="obj\NucuCar.Sensors.csproj.UnmanagedRegistration.cache" /> <_ResolveComReferenceCache Remove="obj\Debug\netcoreapp3.0\NucuCar.Sensors.csproj.ResolveComReference.cache" /> + <_ResolveComReferenceCache Remove="obj\Debug\netcoreapp3.0\NucuCar.Sensors.csproj.ResolveComReference.cache" /> + <_DebugSymbolsIntermediatePath Remove="obj\Debug\netcoreapp3.0\NucuCar.Sensors.pdb" /> + <_DebugSymbolsIntermediatePath Remove="obj\Debug\netcoreapp3.0\NucuCar.Sensors.pdb" /> <_DeploymentManifestEntryPoint Remove="obj\Debug\netcoreapp3.0\NucuCar.Sensors.dll" /> + <_DeploymentManifestEntryPoint Remove="obj\Debug\netcoreapp3.0\NucuCar.Sensors.dll" /> + + + + + + + + + + + + + Both + Public + True + + True + obj/Debug/netcoreapp3.0/ + MSBuild:Compile + diff --git a/NucuCar.Sensors/Program.cs b/NucuCar.Sensors/Program.cs index 4996141..9c298fa 100644 --- a/NucuCar.Sensors/Program.cs +++ b/NucuCar.Sensors/Program.cs @@ -1,3 +1,4 @@ +using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using NucuCar.Sensors.EnvironmentSensor; @@ -10,9 +11,10 @@ namespace NucuCar.Sensors { CreateHostBuilder(args).Build().Run(); } - + public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) - .ConfigureServices((hostContext, services) => { services.AddHostedService(); }); + .ConfigureServices((hostContext, services) => { services.AddHostedService(); }) + .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }); } } \ No newline at end of file diff --git a/NucuCar.Sensors/Protos/EnvironmentSensor.proto b/NucuCar.Sensors/Protos/EnvironmentSensor.proto new file mode 100644 index 0000000..01b153c --- /dev/null +++ b/NucuCar.Sensors/Protos/EnvironmentSensor.proto @@ -0,0 +1,19 @@ +syntax = "proto3"; + +package NucuCarGrpcSensors; + +// The greeting service definition. +service EnvironmentSensorGrpcService { + // Sends a greeting + rpc SayHello (HelloRequest) returns (HelloReply) {} +} + +// The request message containing the user's name. +message HelloRequest { + string name = 1; +} + +// The response message containing the greetings +message HelloReply { + string message = 1; +} \ No newline at end of file diff --git a/NucuCar.Sensors/Readme.md b/NucuCar.Sensors/Readme.md index bb9cbd8..e7a819b 100644 --- a/NucuCar.Sensors/Readme.md +++ b/NucuCar.Sensors/Readme.md @@ -11,5 +11,7 @@ Sensor capabilities: * Humidity * VOC Gas (Currently not implemented in binding) +Note: Currently using the development certificate for gRpc calls. + \ No newline at end of file diff --git a/NucuCar.Sensors/SensorState.cs b/NucuCar.Sensors/SensorState.cs index a065de2..9b84bf4 100644 --- a/NucuCar.Sensors/SensorState.cs +++ b/NucuCar.Sensors/SensorState.cs @@ -3,6 +3,7 @@ namespace NucuCar.Sensors public enum SensorState { Error, + Uninitialized, Initialized } } \ No newline at end of file diff --git a/NucuCar.Sensors/appsettings.Development.json b/NucuCar.Sensors/appsettings.Development.json index e203e94..fe20c40 100644 --- a/NucuCar.Sensors/appsettings.Development.json +++ b/NucuCar.Sensors/appsettings.Development.json @@ -3,6 +3,7 @@ "LogLevel": { "Default": "Debug", "System": "Information", + "Grpc": "Information", "Microsoft": "Information" } } diff --git a/NucuCar.Sensors/appsettings.json b/NucuCar.Sensors/appsettings.json index 8983e0f..0dc062d 100644 --- a/NucuCar.Sensors/appsettings.json +++ b/NucuCar.Sensors/appsettings.json @@ -5,5 +5,16 @@ "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } + }, + "AllowedHosts": "*", + "Kestrel": { + "EndpointDefaults": { + "Protocols": "Http2" + }, + "EndPoints": { + "Https":{ + "Url": "https://localhost:8000" + } + } } -} +} \ No newline at end of file diff --git a/NucuCar.TestClient/NucuCar.TestClient.csproj b/NucuCar.TestClient/NucuCar.TestClient.csproj new file mode 100644 index 0000000..377f3a5 --- /dev/null +++ b/NucuCar.TestClient/NucuCar.TestClient.csproj @@ -0,0 +1,17 @@ + + + + Exe + netcoreapp3.0 + + + + + + + + + + + + diff --git a/NucuCar.TestClient/Program.cs b/NucuCar.TestClient/Program.cs new file mode 100644 index 0000000..07c227d --- /dev/null +++ b/NucuCar.TestClient/Program.cs @@ -0,0 +1,38 @@ +using System; +using System.Net.Http; +using System.Threading.Tasks; +using Grpc.Net.Client; +using NucuCarGrpcSensors; + +namespace NucuCar.TestClient +{ + class Program + { + /* Warning! Before issuing a gRPC call the dev certificate must be trusted or you'll get: + * Detail="Error starting gRPC call: The SSL connection could not be established, see inner exception." + * See: https://docs.microsoft.com/en-us/aspnet/core/security/enforcing-ssl?view=aspnetcore-3.0&tabs=visual-studio#trust-the-aspnet-core-https-development-certificate-on-windows-and-macos + */ + static async Task Main(string[] args) + { + // Used to allow gRPC calls over unsecured HTTP. + AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true); + + // Allow untrusted certificates. + var httpClientHandler = new HttpClientHandler(); + httpClientHandler.ServerCertificateCustomValidationCallback = + HttpClientHandler.DangerousAcceptAnyServerCertificateValidator; + var httpClient = new HttpClient(httpClientHandler); + + + // The port number(5001) must match the port of the gRPC server. + var channel = GrpcChannel.ForAddress("https://localhost:8000", + new GrpcChannelOptions {HttpClient = httpClient}); + var client = new EnvironmentSensorGrpcService.EnvironmentSensorGrpcServiceClient(channel); + var reply = await client.SayHelloAsync( + new HelloRequest {Name = "GreeterClient"}); + Console.WriteLine("Greeting: " + reply.Message); + Console.WriteLine("Press any key to exit..."); + Console.ReadKey(); + } + } +} \ No newline at end of file diff --git a/NucuCar.sln b/NucuCar.sln index 377daba..a5f7632 100644 --- a/NucuCar.sln +++ b/NucuCar.sln @@ -2,6 +2,8 @@ Microsoft Visual Studio Solution File, Format Version 12.00 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NucuCar.Sensors", "NucuCar.Sensors\NucuCar.Sensors.csproj", "{94C44683-F5AF-4D7D-83AE-1F94A81E1E91}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NucuCar.TestClient", "NucuCar.TestClient\NucuCar.TestClient.csproj", "{402BE859-07C7-4C77-8F3A-E727988CCFAD}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -12,5 +14,9 @@ Global {94C44683-F5AF-4D7D-83AE-1F94A81E1E91}.Debug|Any CPU.Build.0 = Debug|Any CPU {94C44683-F5AF-4D7D-83AE-1F94A81E1E91}.Release|Any CPU.ActiveCfg = Release|Any CPU {94C44683-F5AF-4D7D-83AE-1F94A81E1E91}.Release|Any CPU.Build.0 = Release|Any CPU + {402BE859-07C7-4C77-8F3A-E727988CCFAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {402BE859-07C7-4C77-8F3A-E727988CCFAD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {402BE859-07C7-4C77-8F3A-E727988CCFAD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {402BE859-07C7-4C77-8F3A-E727988CCFAD}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal