Add support for Telemetry via Azure-IoT Hub
This commit is contained in:
parent
70c1dc290c
commit
b2ff223ad6
6 changed files with 30 additions and 98 deletions
|
@ -109,12 +109,12 @@ namespace NucuCar.Sensors.EnvironmentSensor
|
|||
return nameof(EnvironmentSensor);
|
||||
}
|
||||
|
||||
public Dictionary<string, double> GetTelemetryData()
|
||||
public Dictionary<string, object> GetTelemetryData()
|
||||
{
|
||||
Dictionary<string, double> returnValue = null;
|
||||
Dictionary<string, object> returnValue = null;
|
||||
if (_lastMeasurement != null)
|
||||
{
|
||||
returnValue = new Dictionary<string, double>
|
||||
returnValue = new Dictionary<string, object>
|
||||
{
|
||||
["temperature"] = _lastMeasurement.Temperature,
|
||||
["humidity"] = _lastMeasurement.Humidity,
|
||||
|
|
|
@ -10,9 +10,8 @@
|
|||
<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.Azure.Devices.Client" Version="1.29.0-preview-002" />
|
||||
<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>
|
||||
|
||||
|
|
|
@ -8,11 +8,7 @@ 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 string _azureIotHubConnectionString;
|
||||
private readonly bool _serviceEnabled;
|
||||
private readonly int _interval;
|
||||
private readonly ILogger _logger;
|
||||
|
@ -20,14 +16,9 @@ namespace NucuCar.Sensors.Telemetry
|
|||
public BackgroundWorker(ILogger<BackgroundWorker> logger, IConfiguration configuration)
|
||||
{
|
||||
_logger = logger;
|
||||
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");
|
||||
_serviceEnabled = configuration.GetValue<bool>("Telemetry:Enabled");
|
||||
_interval = configuration.GetValue<int>("Telemetry:Interval");
|
||||
_azureIotHubConnectionString = configuration.GetValue<string>("Telemetry:AzureIotHubConnectionString");
|
||||
}
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
|
@ -42,13 +33,9 @@ namespace NucuCar.Sensors.Telemetry
|
|||
using var telemetryService = TelemetryService.Instance;
|
||||
|
||||
telemetryService.SetLogger(_logger);
|
||||
telemetryService.ProjectId = _projectId;
|
||||
telemetryService.DeviceId = _deviceId;
|
||||
telemetryService.RegistryId = _registryId;
|
||||
telemetryService.Region = _region;
|
||||
telemetryService.Rs256File = _rs256KeyFile;
|
||||
telemetryService.AzureIotHubConnectionString = _azureIotHubConnectionString;
|
||||
|
||||
await telemetryService.StartAsync();
|
||||
telemetryService.Start();
|
||||
while (!stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
_logger.LogInformation("Publishing telemetry data!");
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace NucuCar.Sensors.Telemetry
|
||||
|
@ -7,6 +6,6 @@ namespace NucuCar.Sensors.Telemetry
|
|||
{
|
||||
string GetIdentifier();
|
||||
/* Dictionary containing the topic and the value */
|
||||
Dictionary<string, double> GetTelemetryData();
|
||||
Dictionary<string, object> GetTelemetryData();
|
||||
}
|
||||
}
|
|
@ -1,99 +1,49 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.Devices.Client;
|
||||
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;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace NucuCar.Sensors.Telemetry
|
||||
{
|
||||
public class TelemetryService : IDisposable
|
||||
{
|
||||
private readonly List<ITelemetrySensor> _registeredSensors;
|
||||
private readonly IManagedMqttClient _mqttClient;
|
||||
private DeviceClient _deviceClient;
|
||||
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; }
|
||||
public string AzureIotHubConnectionString { 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.AddDays(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 StartAsync()
|
||||
public void Start()
|
||||
{
|
||||
_logger.LogInformation("Starting the MQTT client.");
|
||||
ManagedMqttClientOptions options;
|
||||
try
|
||||
{
|
||||
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();
|
||||
_deviceClient = DeviceClient.CreateFromConnectionString(AzureIotHubConnectionString, TransportType.Mqtt);
|
||||
}
|
||||
catch (IOException e)
|
||||
catch (FormatException)
|
||||
{
|
||||
_logger.LogCritical(e.Message);
|
||||
_logger.LogCritical("Can't start telemetry service! Malformed connection string!");
|
||||
throw;
|
||||
}
|
||||
|
||||
await _mqttClient.StartAsync(options);
|
||||
_logger.LogInformation("Started the MQTT client!");
|
||||
}
|
||||
|
||||
|
@ -107,22 +57,23 @@ namespace NucuCar.Sensors.Telemetry
|
|||
_logger.LogWarning($"Warning! Data for {sensor.GetIdentifier()} is null!");
|
||||
continue;
|
||||
}
|
||||
|
||||
await UploadData(data, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UploadData(Dictionary<string, double> data, CancellationToken cancellationToken)
|
||||
private async Task UploadData(Dictionary<string, object> data, CancellationToken cancellationToken)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
_logger.LogInformation("Stopping the MQTT client, cancellation requested.");
|
||||
await _mqttClient.StopAsync();
|
||||
}
|
||||
|
||||
foreach (var entry in data)
|
||||
{
|
||||
await _mqttClient.PublishAsync(entry.Key, entry.Value.ToString(CultureInfo.InvariantCulture));
|
||||
await _deviceClient.CloseAsync(cancellationToken);
|
||||
return;
|
||||
}
|
||||
var messageString = JsonConvert.SerializeObject(data);
|
||||
var message = new Message(Encoding.ASCII.GetBytes(messageString));
|
||||
_logger.LogDebug($"Telemetry message: {message}");
|
||||
await _deviceClient.SendEventAsync(message, cancellationToken);
|
||||
}
|
||||
|
||||
public void RegisterSensor(ITelemetrySensor sensor)
|
||||
|
|
|
@ -2,11 +2,7 @@
|
|||
"Telemetry": {
|
||||
"Enabled": true,
|
||||
"Interval": 3000,
|
||||
"ProjectId": "playground-239221",
|
||||
"DeviceId": "3087236321317137",
|
||||
"RegistryId": "Development",
|
||||
"Region": "europe-west1",
|
||||
"RS256File": "/home/denis/Projects/RiderProjects/NucuCar/NucuCar.Sensors/Certificates/jwt.key"
|
||||
"AzureIotHubConnectionString": "YOUR_IOT_HUB_CONNECTION_STRING"
|
||||
},
|
||||
"EnvironmentSensor": {
|
||||
"Enabled": true,
|
||||
|
@ -26,7 +22,7 @@
|
|||
"Protocols": "Http2"
|
||||
},
|
||||
"EndPoints": {
|
||||
"Https":{
|
||||
"Https": {
|
||||
"Url": "https://0.0.0.0:8000"
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue