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/
|
||||
obj/
|
||||
/packages/
|
||||
|
|
|
@ -8,8 +8,11 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="Grpc.AspNetCore" Version="2.25.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="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" />
|
||||
</ItemGroup>
|
||||
|
||||
|
@ -79,4 +82,8 @@
|
|||
<ItemGroup>
|
||||
<ProjectReference Include="..\NucuCar.Domain\NucuCar.Domain.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Certificates" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
@ -9,6 +8,11 @@ namespace NucuCar.Sensors.Telemetry
|
|||
{
|
||||
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 int _interval;
|
||||
private readonly ILogger _logger;
|
||||
|
@ -19,6 +23,11 @@ namespace NucuCar.Sensors.Telemetry
|
|||
var configSection = configuration.GetSection("Telemetry");
|
||||
_serviceEnabled = configSection.GetValue<bool>("Enabled");
|
||||
_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)
|
||||
|
@ -27,13 +36,23 @@ namespace NucuCar.Sensors.Telemetry
|
|||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await Task.Delay(_interval, stoppingToken);
|
||||
|
||||
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)
|
||||
{
|
||||
_logger.LogInformation("Publishing telemetry data!");
|
||||
await telemetryService.PublishData();
|
||||
await telemetryService.PublishDataAsync(stoppingToken);
|
||||
await Task.Delay(_interval, stoppingToken);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,43 +1,112 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading;
|
||||
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
|
||||
{
|
||||
public class TelemetryService : IDisposable
|
||||
{
|
||||
private readonly List<ITelemetrySensor> _registeredSensors;
|
||||
private readonly IManagedMqttClient _mqttClient;
|
||||
private ILogger _logger;
|
||||
|
||||
/* Singleton Instance */
|
||||
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()
|
||||
{
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
_registeredSensors = new List<ITelemetrySensor>(5);
|
||||
|
||||
_mqttClient = new MqttFactory().CreateManagedMqttClient();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
|
||||
public void SetLogger(ILogger logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,12 @@
|
|||
{
|
||||
"Telemetry": {
|
||||
"Enabled": true,
|
||||
"Interval": 5000
|
||||
"Interval": 5000,
|
||||
"ProjectId": "playground-239221",
|
||||
"DeviceId": "3087236321317137",
|
||||
"RegistryId": "Development",
|
||||
"Region": "europe-west1",
|
||||
"RS256File": "Certificates\\key.key"
|
||||
},
|
||||
"EnvironmentSensor": {
|
||||
"Enabled": true,
|
||||
|
|
Loading…
Reference in a new issue