From 5b4355d43ca7c7c456ea5480f2a8e637436f66bd Mon Sep 17 00:00:00 2001 From: Thomas Fransolet Date: Sat, 2 Jan 2021 16:53:06 +0100 Subject: [PATCH] Two mqtt client - Local and online --- .../Controllers/Devices/DeviceController.cs | 32 ++++- MyCore/Extensions/AppSettingsProvider.cs | 6 + .../AspCoreMqttClientOptionBuilder.cs | 10 ++ MyCore/Extensions/BrokerHostSettings.cs | 6 + MyCore/Extensions/ClientSettings.cs | 7 + MyCore/Extensions/IMqttClientService.cs | 7 + MyCore/Extensions/MqttClientOnlineService.cs | 135 ++++++++++++++++++ .../MqttClientOnlineServiceProvider.cs | 12 ++ MyCore/Extensions/MqttClientService.cs | 6 + .../Extensions/ServiceCollectionExtension.cs | 46 +++++- MyCore/Startup.cs | 9 ++ MyCore/appsettings.json | 13 ++ 12 files changed, 284 insertions(+), 5 deletions(-) create mode 100644 MyCore/Extensions/MqttClientOnlineService.cs create mode 100644 MyCore/Extensions/MqttClientOnlineServiceProvider.cs diff --git a/MyCore/Controllers/Devices/DeviceController.cs b/MyCore/Controllers/Devices/DeviceController.cs index 8402995..8d4cf02 100644 --- a/MyCore/Controllers/Devices/DeviceController.cs +++ b/MyCore/Controllers/Devices/DeviceController.cs @@ -27,14 +27,16 @@ namespace MyCore.Controllers.Devices private LocationDatabaseService _LocationDatabaseService; private UserDatabaseService _UserDatabaseService; private readonly IMqttClientService _mqttClientService; + private readonly IMqttOnlineClientService _mqttOnlineClientService; - public DeviceController(DeviceDatabaseService DeviceDatabaseService, ProviderDatabaseService ProviderDatabaseService, LocationDatabaseService LocationDatabaseService, UserDatabaseService UserDatabaseService, MqttClientServiceProvider provider) + public DeviceController(DeviceDatabaseService DeviceDatabaseService, ProviderDatabaseService ProviderDatabaseService, LocationDatabaseService LocationDatabaseService, UserDatabaseService UserDatabaseService, MqttClientServiceProvider provider, MqttClientOnlineServiceProvider onlineProvider) { this._DeviceDatabaseService = DeviceDatabaseService; this._ProviderDatabaseService = ProviderDatabaseService; this._LocationDatabaseService = LocationDatabaseService; this._UserDatabaseService = UserDatabaseService; this._mqttClientService = provider.MqttClientService; + this._mqttOnlineClientService = onlineProvider.MqttOnlineClientService; } // GET: Devices @@ -171,7 +173,7 @@ namespace MyCore.Controllers.Devices /// User Id [ProducesResponseType(typeof(List), 200)] [HttpGet("zigbee2Mqtt/{userId}")] - public ObjectResult GetDevicesFromZigbee2Mqtt(string userId) + public async Task GetDevicesFromZigbee2Mqtt(string userId) { try { @@ -184,6 +186,32 @@ namespace MyCore.Controllers.Devices // GET ALL LOCAL DEVICES var devices = MqttClientService.devices; + // Test mqtt + await MqttClientService.PublishMessage("test", "zdz").ContinueWith(res => { + + if (res.Status == TaskStatus.RanToCompletion) + { + + } + else + { + throw new Exception("Publish error"); + } + }); + + // Test online mqtt + await MqttClientOnlineService.PublishMessage("test", "zdz").ContinueWith(res => { + + if (res.Status == TaskStatus.RanToCompletion) + { + + } + else + { + throw new Exception("Publish error"); + } + }); + return new OkObjectResult(devices); } catch (InvalidOperationException ex) diff --git a/MyCore/Extensions/AppSettingsProvider.cs b/MyCore/Extensions/AppSettingsProvider.cs index 5d6b073..18996ef 100644 --- a/MyCore/Extensions/AppSettingsProvider.cs +++ b/MyCore/Extensions/AppSettingsProvider.cs @@ -5,4 +5,10 @@ public static BrokerHostSettings BrokerHostSettings; public static ClientSettings ClientSettings; } + + public class AppSettingsOnlineProvider + { + public static BrokerOnlineHostSettings BrokerHostOnlineSettings; + public static ClientOnlineSettings ClientOnlineSettings; + } } diff --git a/MyCore/Extensions/AspCoreMqttClientOptionBuilder.cs b/MyCore/Extensions/AspCoreMqttClientOptionBuilder.cs index 71d0b63..c9fe00b 100644 --- a/MyCore/Extensions/AspCoreMqttClientOptionBuilder.cs +++ b/MyCore/Extensions/AspCoreMqttClientOptionBuilder.cs @@ -12,4 +12,14 @@ namespace Mqtt.Client.AspNetCore.Options ServiceProvider = serviceProvider; } } + + public class AspCoreMqttOnlineClientOptionBuilder : MqttClientOptionsBuilder + { + public IServiceProvider ServiceOnlineProvider { get; } + + public AspCoreMqttOnlineClientOptionBuilder(IServiceProvider serviceProvider) + { + ServiceOnlineProvider = serviceProvider; + } + } } diff --git a/MyCore/Extensions/BrokerHostSettings.cs b/MyCore/Extensions/BrokerHostSettings.cs index feb8efe..5244f52 100644 --- a/MyCore/Extensions/BrokerHostSettings.cs +++ b/MyCore/Extensions/BrokerHostSettings.cs @@ -5,4 +5,10 @@ public string Host { set; get; } public int Port { set; get; } } + + public class BrokerOnlineHostSettings + { + public string Host { set; get; } + public int Port { set; get; } + } } diff --git a/MyCore/Extensions/ClientSettings.cs b/MyCore/Extensions/ClientSettings.cs index ca876a9..f250753 100644 --- a/MyCore/Extensions/ClientSettings.cs +++ b/MyCore/Extensions/ClientSettings.cs @@ -6,4 +6,11 @@ public string UserName { set; get; } public string Password { set; get; } } + + public class ClientOnlineSettings + { + public string Id { set; get; } + public string UserName { set; get; } + public string Password { set; get; } + } } diff --git a/MyCore/Extensions/IMqttClientService.cs b/MyCore/Extensions/IMqttClientService.cs index 3157670..45b739a 100644 --- a/MyCore/Extensions/IMqttClientService.cs +++ b/MyCore/Extensions/IMqttClientService.cs @@ -11,4 +11,11 @@ namespace Mqtt.Client.AspNetCore.Services IMqttApplicationMessageReceivedHandler { } + + public interface IMqttOnlineClientService : IHostedService, + IMqttClientConnectedHandler, + IMqttClientDisconnectedHandler, + IMqttApplicationMessageReceivedHandler + { + } } diff --git a/MyCore/Extensions/MqttClientOnlineService.cs b/MyCore/Extensions/MqttClientOnlineService.cs new file mode 100644 index 0000000..cc1c32d --- /dev/null +++ b/MyCore/Extensions/MqttClientOnlineService.cs @@ -0,0 +1,135 @@ +using MQTTnet; +using MQTTnet.Client; +using MQTTnet.Client.Connecting; +using MQTTnet.Client.Disconnecting; +using MQTTnet.Client.Options; +using MyCore.Interfaces.Models; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Mqtt.Client.AspNetCore.Services +{ + public class MqttClientOnlineService : IMqttOnlineClientService + { + private static IMqttClient mqttClient; + private IMqttClientOptions onlineOptions; + public static List devices = new List(); + + public MqttClientOnlineService(IMqttClientOptions options) + { + this.onlineOptions = options; + mqttClient = new MqttFactory().CreateMqttClient(); + ConfigureMqttClient(); + } + + private void ConfigureMqttClient() + { + mqttClient.ConnectedHandler = this; + mqttClient.DisconnectedHandler = this; + mqttClient.ApplicationMessageReceivedHandler = this; + } + + public Task HandleApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs e) + { + Console.WriteLine("### RECEIVED APPLICATION MESSAGE ###"); + Console.WriteLine($"+ Topic = {e.ApplicationMessage.Topic}"); + var payload = ""; + if (e.ApplicationMessage.Payload != null) + { + Console.WriteLine($"+ Payload = {Encoding.UTF8.GetString(e.ApplicationMessage.Payload)}"); + payload = Encoding.UTF8.GetString(e.ApplicationMessage.Payload); + } + + + Console.WriteLine($"+ QoS = {e.ApplicationMessage.QualityOfServiceLevel}"); + Console.WriteLine($"+ Retain = {e.ApplicationMessage.Retain}"); + Console.WriteLine(); + + var topic = e.ApplicationMessage.Topic; + + switch (topic) + { + case "zigbee2mqtt/bridge/config/devices": + try + { + var test = JsonConvert.DeserializeObject>(payload); + devices = test; + + // TODO Update in DB, current devices state + } + catch (Exception ex) + { + Console.WriteLine($"Error during retrieving devices ! Exception: {ex}"); + } + break; + } + + //return new Task(null); + // TODO check what to do + //await PublishMessage("test", "teeest"); + return null; + } + + public async Task HandleConnectedAsync(MqttClientConnectedEventArgs eventArgs) + { + System.Console.WriteLine("connected"); + //await mqttClient.SubscribeAsync("hello/world"); + await mqttClient.SubscribeAsync("#"); + await PublishMessage("zigbee2mqtt/bridge/config/devices/get", ""); + } + + public async Task HandleDisconnectedAsync(MqttClientDisconnectedEventArgs eventArgs) + { + if (!mqttClient.IsConnected) + { + await mqttClient.ReconnectAsync(); + } + //throw new System.NotImplementedException(); + } + + public async Task StartAsync(CancellationToken cancellationToken) + { + await mqttClient.ConnectAsync(onlineOptions); + if (!mqttClient.IsConnected) + { + await mqttClient.ReconnectAsync(); + } + } + + public async Task StopAsync(CancellationToken cancellationToken) + { + if(cancellationToken.IsCancellationRequested) + { + var disconnectOption = new MqttClientDisconnectOptions + { + ReasonCode = MqttClientDisconnectReason.NormalDisconnection, + ReasonString = "NormalDiconnection" + }; + await mqttClient.DisconnectAsync(disconnectOption, cancellationToken); + } + await mqttClient.DisconnectAsync(); + } + + public static async Task PublishMessage(string topic, string message) + { + var mqttMessage = new MqttApplicationMessageBuilder() + .WithTopic(topic) + .WithPayload(message) + .WithExactlyOnceQoS() + .WithRetainFlag() + .Build(); + + if (mqttClient.IsConnected) + await mqttClient.PublishAsync(mqttMessage); + } + + public static List GetDevices() + { + return devices; + } + } +} diff --git a/MyCore/Extensions/MqttClientOnlineServiceProvider.cs b/MyCore/Extensions/MqttClientOnlineServiceProvider.cs new file mode 100644 index 0000000..fa43348 --- /dev/null +++ b/MyCore/Extensions/MqttClientOnlineServiceProvider.cs @@ -0,0 +1,12 @@ +namespace Mqtt.Client.AspNetCore.Services +{ + public class MqttClientOnlineServiceProvider + { + public readonly IMqttOnlineClientService MqttOnlineClientService; + + public MqttClientOnlineServiceProvider(IMqttOnlineClientService mqttOnlineClientService) + { + MqttOnlineClientService = mqttOnlineClientService; + } + } +} diff --git a/MyCore/Extensions/MqttClientService.cs b/MyCore/Extensions/MqttClientService.cs index 5bd14a3..f92383a 100644 --- a/MyCore/Extensions/MqttClientService.cs +++ b/MyCore/Extensions/MqttClientService.cs @@ -23,6 +23,12 @@ namespace Mqtt.Client.AspNetCore.Services public MqttClientService(IMqttClientOptions options) { this.options = options; + this.options = new MqttClientOptionsBuilder() + .WithClientId("ApiService") + .WithTcpServer("192.168.31.140") // TODO replace by localhost + .WithCredentials("mqtt", "mqtt") + .WithCleanSession() + .Build(); mqttClient = new MqttFactory().CreateMqttClient(); ConfigureMqttClient(); } diff --git a/MyCore/Extensions/ServiceCollectionExtension.cs b/MyCore/Extensions/ServiceCollectionExtension.cs index 7fc483c..1b24e6a 100644 --- a/MyCore/Extensions/ServiceCollectionExtension.cs +++ b/MyCore/Extensions/ServiceCollectionExtension.cs @@ -26,14 +26,32 @@ namespace MyCore.Service.Extensions return services; } + public static IServiceCollection AddMqttClientOnlineHostedService(this IServiceCollection services) + { + services.AddMqttClientOnlineServiceWithConfig(aspOnlineOptionBuilder => + { + var clientSettings = AppSettingsOnlineProvider.ClientOnlineSettings; + var brokerHostSettings = AppSettingsOnlineProvider.BrokerHostOnlineSettings; + + aspOnlineOptionBuilder + .WithCredentials(clientSettings.UserName, clientSettings.Password) + .WithClientId(clientSettings.Id) + .WithTcpServer(brokerHostSettings.Host, brokerHostSettings.Port); + }); + return services; + } + + + private static IServiceCollection AddMqttClientServiceWithConfig(this IServiceCollection services, Action configure) { - services.AddSingleton(serviceProvider => + // No need as we implement options in service (localhost) + /*services.AddSingleton(serviceProvider => { var optionBuilder = new AspCoreMqttClientOptionBuilder(serviceProvider); configure(optionBuilder); return optionBuilder.Build(); - }); + });*/ services.AddSingleton(); services.AddSingleton(serviceProvider => { @@ -47,6 +65,28 @@ namespace MyCore.Service.Extensions }); return services; } - + + private static IServiceCollection AddMqttClientOnlineServiceWithConfig(this IServiceCollection services, Action configure) + { + services.AddSingleton(serviceOnlineProvider => + { + var optionBuilder = new AspCoreMqttOnlineClientOptionBuilder(serviceOnlineProvider); + configure(optionBuilder); + return optionBuilder.Build(); + }); + services.AddSingleton(); + services.AddSingleton(serviceProvider => + { + return serviceProvider.GetService(); + }); + services.AddSingleton(serviceProvider => + { + var mqttOnlineClientService = serviceProvider.GetService(); + var mqttOnlineClientServiceProvider = new MqttClientOnlineServiceProvider(mqttOnlineClientService); + return mqttOnlineClientServiceProvider; + }); + return services; + } + } } diff --git a/MyCore/Startup.cs b/MyCore/Startup.cs index f3b4917..d641dd0 100644 --- a/MyCore/Startup.cs +++ b/MyCore/Startup.cs @@ -70,6 +70,10 @@ namespace MyCore BrokerHostSettings brokerHostSettings = new BrokerHostSettings(); Configuration.GetSection(nameof(BrokerHostSettings)).Bind(brokerHostSettings); AppSettingsProvider.BrokerHostSettings = brokerHostSettings; + + BrokerOnlineHostSettings brokerOnlineHostSettings = new BrokerOnlineHostSettings(); + Configuration.GetSection(nameof(BrokerOnlineHostSettings)).Bind(brokerOnlineHostSettings); + AppSettingsOnlineProvider.BrokerHostOnlineSettings = brokerOnlineHostSettings; } private void MapClientSettings() @@ -77,6 +81,10 @@ namespace MyCore ClientSettings clientSettings = new ClientSettings(); Configuration.GetSection(nameof(ClientSettings)).Bind(clientSettings); AppSettingsProvider.ClientSettings = clientSettings; + + ClientOnlineSettings clientOnlineSettings = new ClientOnlineSettings(); + Configuration.GetSection(nameof(ClientOnlineSettings)).Bind(clientOnlineSettings); + AppSettingsOnlineProvider.ClientOnlineSettings = clientOnlineSettings; } // This method gets called by the runtime. Use this method to add services to the container. @@ -196,6 +204,7 @@ namespace MyCore services.AddScoped(); services.AddMqttClientHostedService(); + services.AddMqttClientOnlineHostedService(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. diff --git a/MyCore/appsettings.json b/MyCore/appsettings.json index f80fe42..dd5817a 100644 --- a/MyCore/appsettings.json +++ b/MyCore/appsettings.json @@ -16,6 +16,7 @@ "AccessTokenExpiration": 86400, "RefreshTokenExpiration": 518400 }, + "SecuritySettings": { "Secret": "azertyuiopqsdfgh", "Issuer": "MyCore", @@ -23,6 +24,7 @@ "IdType": "Name", "TokenExpiryInHours": 2 }, + "BrokerHostSettings": { "Host": "192.168.31.140", "Port": 1883 @@ -32,5 +34,16 @@ "Id": "5eb020f043ba8930506acbdd", "UserName": "mqtt", "Password": "mqtt" + }, + + "BrokerOnlineHostSettings": { + "Host": "myhomie.be", + "Port": 1883 + }, + + "ClientOnlineSettings": { + "Id": "5eb020f043ba8930506acbaa", + "UserName": "thomas", + "Password": "MyCore,1" } }