Attempt to add Google Cloud Platform as a MQTT server
This commit is contained in:
parent
fb4034773c
commit
572c12d43f
5 changed files with 113 additions and 7 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
||||||
|
NucuCar.Sensors/Certificates/*
|
||||||
bin/
|
bin/
|
||||||
obj/
|
obj/
|
||||||
/packages/
|
/packages/
|
||||||
|
|
|
@ -8,8 +8,11 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Grpc.AspNetCore" Version="2.25.0" />
|
<PackageReference Include="Grpc.AspNetCore" Version="2.25.0" />
|
||||||
<PackageReference Include="Iot.Device.Bindings" Version="1.0.0" />
|
<PackageReference Include="Iot.Device.Bindings" Version="1.0.0" />
|
||||||
|
<PackageReference Include="jose-jwt" Version="2.5.0" />
|
||||||
<PackageReference Include="libgrpc_csharp_ext.arm7" Version="1.0.8" />
|
<PackageReference Include="libgrpc_csharp_ext.arm7" Version="1.0.8" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="3.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="3.0.0" />
|
||||||
|
<PackageReference Include="MQTTnet.Extensions.ManagedClient" Version="3.0.8" />
|
||||||
|
<PackageReference Include="Portable.BouncyCastle" Version="1.8.5.2" />
|
||||||
<PackageReference Include="System.Device.Gpio" Version="1.0.0" />
|
<PackageReference Include="System.Device.Gpio" Version="1.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
@ -79,4 +82,8 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\NucuCar.Domain\NucuCar.Domain.csproj" />
|
<ProjectReference Include="..\NucuCar.Domain\NucuCar.Domain.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Certificates" />
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
using System;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
|
@ -9,6 +8,11 @@ namespace NucuCar.Sensors.Telemetry
|
||||||
{
|
{
|
||||||
public class BackgroundWorker : BackgroundService
|
public class BackgroundWorker : BackgroundService
|
||||||
{
|
{
|
||||||
|
private readonly string _projectId;
|
||||||
|
private readonly string _region;
|
||||||
|
private readonly string _registryId;
|
||||||
|
private readonly string _deviceId;
|
||||||
|
private readonly string _rs256KeyFile;
|
||||||
private readonly bool _serviceEnabled;
|
private readonly bool _serviceEnabled;
|
||||||
private readonly int _interval;
|
private readonly int _interval;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
|
@ -19,6 +23,11 @@ namespace NucuCar.Sensors.Telemetry
|
||||||
var configSection = configuration.GetSection("Telemetry");
|
var configSection = configuration.GetSection("Telemetry");
|
||||||
_serviceEnabled = configSection.GetValue<bool>("Enabled");
|
_serviceEnabled = configSection.GetValue<bool>("Enabled");
|
||||||
_interval = configSection.GetValue<int>("Interval");
|
_interval = configSection.GetValue<int>("Interval");
|
||||||
|
_projectId = configSection.GetValue<string>("ProjectId");
|
||||||
|
_region = configSection.GetValue<string>("Region");
|
||||||
|
_registryId = configSection.GetValue<string>("RegistryId");
|
||||||
|
_deviceId = configSection.GetValue<string>("DeviceId");
|
||||||
|
_rs256KeyFile = configSection.GetValue<string>("RS256File");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||||
|
@ -27,13 +36,23 @@ namespace NucuCar.Sensors.Telemetry
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await Task.Delay(_interval, stoppingToken);
|
await Task.Delay(_interval, stoppingToken);
|
||||||
|
|
||||||
using var telemetryService = TelemetryService.Instance;
|
using var telemetryService = TelemetryService.Instance;
|
||||||
|
|
||||||
|
telemetryService.SetLogger(_logger);
|
||||||
|
telemetryService.ProjectId = _projectId;
|
||||||
|
telemetryService.DeviceId = _deviceId;
|
||||||
|
telemetryService.RegistryId = _registryId;
|
||||||
|
telemetryService.Region = _region;
|
||||||
|
telemetryService.Rs256File = _rs256KeyFile;
|
||||||
|
|
||||||
|
await telemetryService.StartAsync();
|
||||||
while (!stoppingToken.IsCancellationRequested)
|
while (!stoppingToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Publishing telemetry data!");
|
_logger.LogInformation("Publishing telemetry data!");
|
||||||
await telemetryService.PublishData();
|
await telemetryService.PublishDataAsync(stoppingToken);
|
||||||
await Task.Delay(_interval, stoppingToken);
|
await Task.Delay(_interval, stoppingToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,43 +1,112 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using MQTTnet;
|
||||||
|
using MQTTnet.Client.Options;
|
||||||
|
using MQTTnet.Extensions.ManagedClient;
|
||||||
|
using Org.BouncyCastle.Crypto;
|
||||||
|
using Org.BouncyCastle.Crypto.Parameters;
|
||||||
|
using Org.BouncyCastle.OpenSsl;
|
||||||
|
using Org.BouncyCastle.Security;
|
||||||
|
|
||||||
namespace NucuCar.Sensors.Telemetry
|
namespace NucuCar.Sensors.Telemetry
|
||||||
{
|
{
|
||||||
public class TelemetryService : IDisposable
|
public class TelemetryService : IDisposable
|
||||||
{
|
{
|
||||||
private readonly List<ITelemetrySensor> _registeredSensors;
|
private readonly List<ITelemetrySensor> _registeredSensors;
|
||||||
|
private readonly IManagedMqttClient _mqttClient;
|
||||||
|
private ILogger _logger;
|
||||||
|
|
||||||
/* Singleton Instance */
|
/* Singleton Instance */
|
||||||
public static TelemetryService Instance { get; } = new TelemetryService();
|
public static TelemetryService Instance { get; } = new TelemetryService();
|
||||||
|
public string ProjectId { get; set; }
|
||||||
|
public string Region { get; set; }
|
||||||
|
public string RegistryId { get; set; }
|
||||||
|
public string DeviceId { get; set; }
|
||||||
|
public string Rs256File { get; set; }
|
||||||
|
|
||||||
static TelemetryService()
|
static TelemetryService()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string GetMqttPassword()
|
||||||
|
{
|
||||||
|
string jwt;
|
||||||
|
AsymmetricCipherKeyPair keyPair;
|
||||||
|
|
||||||
|
using (var sr = new StreamReader(Rs256File))
|
||||||
|
{
|
||||||
|
var pr = new PemReader(sr);
|
||||||
|
keyPair = (AsymmetricCipherKeyPair) pr.ReadObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
var rsaParams = DotNetUtilities.ToRSAParameters((RsaPrivateCrtKeyParameters)keyPair.Private);
|
||||||
|
|
||||||
|
using (var rsa = new RSACryptoServiceProvider())
|
||||||
|
{
|
||||||
|
rsa.ImportParameters(rsaParams);
|
||||||
|
jwt = Jose.JWT.Encode(new Dictionary<string, object>()
|
||||||
|
{
|
||||||
|
["iat"] = DateTime.UtcNow,
|
||||||
|
["exp"] = DateTime.UtcNow.AddMinutes(60),
|
||||||
|
["aud"] = ProjectId
|
||||||
|
}, rsa, Jose.JwsAlgorithm.RS256);
|
||||||
|
}
|
||||||
|
|
||||||
|
return jwt;
|
||||||
|
}
|
||||||
|
|
||||||
private TelemetryService()
|
private TelemetryService()
|
||||||
{
|
{
|
||||||
_registeredSensors = new List<ITelemetrySensor>(5);
|
_registeredSensors = new List<ITelemetrySensor>(5);
|
||||||
|
|
||||||
|
_mqttClient = new MqttFactory().CreateManagedMqttClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task PublishData()
|
public async Task StartAsync()
|
||||||
|
{
|
||||||
|
var options = new ManagedMqttClientOptionsBuilder()
|
||||||
|
.WithAutoReconnectDelay(TimeSpan.FromSeconds(5))
|
||||||
|
.WithClientOptions(new MqttClientOptionsBuilder()
|
||||||
|
.WithClientId($"projects/{ProjectId}/locations/{Region}/registries/{RegistryId}/devices/{DeviceId}")
|
||||||
|
.WithCredentials("unused", GetMqttPassword())
|
||||||
|
.WithTcpServer("mqtt.googleapis.com")
|
||||||
|
.WithTls().Build())
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
_logger.LogInformation("Starting the MQTT client.");
|
||||||
|
await _mqttClient.StartAsync(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task PublishDataAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
foreach (var sensor in _registeredSensors)
|
foreach (var sensor in _registeredSensors)
|
||||||
{
|
{
|
||||||
var data = sensor.GetTelemetryData();
|
var data = sensor.GetTelemetryData();
|
||||||
await UploadData(data);
|
await UploadData(data, cancellationToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task UploadData(Dictionary<string, double> data)
|
private async Task UploadData(Dictionary<string, double> data, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Stopping the MQTT client, cancellation requested.");
|
||||||
|
await _mqttClient.StopAsync();
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var entry in data)
|
foreach (var entry in data)
|
||||||
{
|
{
|
||||||
// TODO: Publish data to IoTCore
|
await _mqttClient.PublishAsync(entry.Key, entry.Value.ToString(CultureInfo.InvariantCulture));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,5 +119,10 @@ namespace NucuCar.Sensors.Telemetry
|
||||||
{
|
{
|
||||||
_registeredSensors.Remove(sensor);
|
_registeredSensors.Remove(sensor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetLogger(ILogger logger)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,7 +1,12 @@
|
||||||
{
|
{
|
||||||
"Telemetry": {
|
"Telemetry": {
|
||||||
"Enabled": true,
|
"Enabled": true,
|
||||||
"Interval": 5000
|
"Interval": 5000,
|
||||||
|
"ProjectId": "playground-239221",
|
||||||
|
"DeviceId": "3087236321317137",
|
||||||
|
"RegistryId": "Development",
|
||||||
|
"Region": "europe-west1",
|
||||||
|
"RS256File": "Certificates\\key.key"
|
||||||
},
|
},
|
||||||
"EnvironmentSensor": {
|
"EnvironmentSensor": {
|
||||||
"Enabled": true,
|
"Enabled": true,
|
||||||
|
|
Loading…
Reference in a new issue