diff --git a/MyCore.Interfaces/Models/MyControlPanel/Database/UserInfo.cs b/MyCore.Interfaces/Models/MyControlPanel/Database/UserInfo.cs index 0f2f5f2..dde280e 100644 --- a/MyCore.Interfaces/Models/MyControlPanel/Database/UserInfo.cs +++ b/MyCore.Interfaces/Models/MyControlPanel/Database/UserInfo.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -//using AspNetCore.Security.Jwt; using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; using MyCore.Interfaces.DTO; @@ -13,7 +12,7 @@ namespace MyCore.Interfaces.Models /// /// User Information /// - public class UserInfo //: IAuthenticationUser // TODO ! + public class UserInfo { [BsonId] [BsonRepresentation(BsonType.ObjectId)] diff --git a/MyCore/Controllers/Devices/DeviceController.cs b/MyCore/Controllers/Devices/DeviceController.cs index 1faf8a7..8402995 100644 --- a/MyCore/Controllers/Devices/DeviceController.cs +++ b/MyCore/Controllers/Devices/DeviceController.cs @@ -8,6 +8,7 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using MongoDB.Bson; +using Mqtt.Client.AspNetCore.Services; using MyCore.Interfaces.DTO; using MyCore.Interfaces.Models; using MyCore.Services; @@ -25,13 +26,15 @@ namespace MyCore.Controllers.Devices private ProviderDatabaseService _ProviderDatabaseService; private LocationDatabaseService _LocationDatabaseService; private UserDatabaseService _UserDatabaseService; + private readonly IMqttClientService _mqttClientService; - public DeviceController(DeviceDatabaseService DeviceDatabaseService, ProviderDatabaseService ProviderDatabaseService, LocationDatabaseService LocationDatabaseService, UserDatabaseService UserDatabaseService) + public DeviceController(DeviceDatabaseService DeviceDatabaseService, ProviderDatabaseService ProviderDatabaseService, LocationDatabaseService LocationDatabaseService, UserDatabaseService UserDatabaseService, MqttClientServiceProvider provider) { this._DeviceDatabaseService = DeviceDatabaseService; this._ProviderDatabaseService = ProviderDatabaseService; this._LocationDatabaseService = LocationDatabaseService; this._UserDatabaseService = UserDatabaseService; + this._mqttClientService = provider.MqttClientService; } // GET: Devices @@ -162,6 +165,37 @@ namespace MyCore.Controllers.Devices } } + /// + /// Get all zigbee2Mqtt devices + /// + /// User Id + [ProducesResponseType(typeof(List), 200)] + [HttpGet("zigbee2Mqtt/{userId}")] + public ObjectResult GetDevicesFromZigbee2Mqtt(string userId) + { + try + { + if (userId == null) + throw new InvalidOperationException("User not found"); + + if (!UserService.IsExist(_UserDatabaseService, userId)) + throw new KeyNotFoundException("User not found"); + + // GET ALL LOCAL DEVICES + var devices = MqttClientService.devices; + + return new OkObjectResult(devices); + } + catch (InvalidOperationException ex) + { + return new BadRequestObjectResult(ex.Message) { StatusCode = 400 }; + } + catch (Exception ex) + { + return new ObjectResult(ex.Message) { StatusCode = 500 }; + } + } + /// /// Create devices from provider /// @@ -178,10 +212,23 @@ namespace MyCore.Controllers.Devices if (!UserService.IsExist(_UserDatabaseService, userId)) throw new KeyNotFoundException("User not found"); + // Test mqtt + await MqttClientService.PublishMessage("test", "zdz").ContinueWith(res => { + + if (res.Status == TaskStatus.RanToCompletion) + { + + } + else { + throw new Exception("Publish error"); + } + }); + + var test = MqttClientService.devices; // Peut etre juste mettre un ok pour ajout zigbee vu qu'on fait le get device lors de la connexion. List devicesCreated = await DeviceService.CreateFromZigbee(this._DeviceDatabaseService, this._ProviderDatabaseService, this._LocationDatabaseService, userId); - return new OkObjectResult(devicesCreated); + return new OkObjectResult(test); } catch (InvalidOperationException ex) { diff --git a/MyCore/Extensions/AppSettingsProvider.cs b/MyCore/Extensions/AppSettingsProvider.cs new file mode 100644 index 0000000..5d6b073 --- /dev/null +++ b/MyCore/Extensions/AppSettingsProvider.cs @@ -0,0 +1,8 @@ +namespace Mqtt.Client.AspNetCore.Settings +{ + public class AppSettingsProvider + { + public static BrokerHostSettings BrokerHostSettings; + public static ClientSettings ClientSettings; + } +} diff --git a/MyCore/Extensions/AspCoreMqttClientOptionBuilder.cs b/MyCore/Extensions/AspCoreMqttClientOptionBuilder.cs new file mode 100644 index 0000000..71d0b63 --- /dev/null +++ b/MyCore/Extensions/AspCoreMqttClientOptionBuilder.cs @@ -0,0 +1,15 @@ +using MQTTnet.Client.Options; +using System; + +namespace Mqtt.Client.AspNetCore.Options +{ + public class AspCoreMqttClientOptionBuilder : MqttClientOptionsBuilder + { + public IServiceProvider ServiceProvider { get; } + + public AspCoreMqttClientOptionBuilder(IServiceProvider serviceProvider) + { + ServiceProvider = serviceProvider; + } + } +} diff --git a/MyCore/Extensions/BrokerHostSettings.cs b/MyCore/Extensions/BrokerHostSettings.cs new file mode 100644 index 0000000..feb8efe --- /dev/null +++ b/MyCore/Extensions/BrokerHostSettings.cs @@ -0,0 +1,8 @@ +namespace Mqtt.Client.AspNetCore.Settings +{ + public class BrokerHostSettings + { + public string Host { set; get; } + public int Port { set; get; } + } +} diff --git a/MyCore/Extensions/ClientSettings.cs b/MyCore/Extensions/ClientSettings.cs new file mode 100644 index 0000000..ca876a9 --- /dev/null +++ b/MyCore/Extensions/ClientSettings.cs @@ -0,0 +1,9 @@ +namespace Mqtt.Client.AspNetCore.Settings +{ + public class ClientSettings + { + public string Id { set; get; } + public string UserName { set; get; } + public string Password { set; get; } + } +} diff --git a/MyCore/Extensions/ExtarnalService.cs b/MyCore/Extensions/ExtarnalService.cs new file mode 100644 index 0000000..3569e09 --- /dev/null +++ b/MyCore/Extensions/ExtarnalService.cs @@ -0,0 +1,11 @@ +namespace Mqtt.Client.AspNetCore.Services +{ + public class ExtarnalService + { + private readonly IMqttClientService mqttClientService; + public ExtarnalService(MqttClientServiceProvider provider) + { + mqttClientService = provider.MqttClientService; + } + } +} diff --git a/MyCore/Extensions/IMqttClientService.cs b/MyCore/Extensions/IMqttClientService.cs new file mode 100644 index 0000000..3157670 --- /dev/null +++ b/MyCore/Extensions/IMqttClientService.cs @@ -0,0 +1,14 @@ +using Microsoft.Extensions.Hosting; +using MQTTnet.Client.Connecting; +using MQTTnet.Client.Disconnecting; +using MQTTnet.Client.Receiving; + +namespace Mqtt.Client.AspNetCore.Services +{ + public interface IMqttClientService : IHostedService, + IMqttClientConnectedHandler, + IMqttClientDisconnectedHandler, + IMqttApplicationMessageReceivedHandler + { + } +} diff --git a/MyCore/Extensions/MqttClientService.cs b/MyCore/Extensions/MqttClientService.cs new file mode 100644 index 0000000..5bd14a3 --- /dev/null +++ b/MyCore/Extensions/MqttClientService.cs @@ -0,0 +1,136 @@ +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 MqttClientService : IMqttClientService + { + private static IMqttClient mqttClient; + private IMqttClientOptions options; + public static List devices = new List(); + + + public MqttClientService(IMqttClientOptions options) + { + this.options = 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(options); + 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/MqttClientServiceProvider.cs b/MyCore/Extensions/MqttClientServiceProvider.cs new file mode 100644 index 0000000..1223eb6 --- /dev/null +++ b/MyCore/Extensions/MqttClientServiceProvider.cs @@ -0,0 +1,12 @@ +namespace Mqtt.Client.AspNetCore.Services +{ + public class MqttClientServiceProvider + { + public readonly IMqttClientService MqttClientService; + + public MqttClientServiceProvider(IMqttClientService mqttClientService) + { + MqttClientService = mqttClientService; + } + } +} diff --git a/MyCore/Extensions/ServiceCollectionExtension.cs b/MyCore/Extensions/ServiceCollectionExtension.cs new file mode 100644 index 0000000..7fc483c --- /dev/null +++ b/MyCore/Extensions/ServiceCollectionExtension.cs @@ -0,0 +1,52 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Mqtt.Client.AspNetCore.Options; +using Mqtt.Client.AspNetCore.Services; +using Mqtt.Client.AspNetCore.Settings; +using MQTTnet.Client.Options; +using System; + +namespace MyCore.Service.Extensions +{ + public static class ServiceCollectionExtension + { + + public static IServiceCollection AddMqttClientHostedService(this IServiceCollection services) + { + services.AddMqttClientServiceWithConfig(aspOptionBuilder => + { + var clientSettings = AppSettingsProvider.ClientSettings; + var brokerHostSettings = AppSettingsProvider.BrokerHostSettings; + + aspOptionBuilder + .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 => + { + var optionBuilder = new AspCoreMqttClientOptionBuilder(serviceProvider); + configure(optionBuilder); + return optionBuilder.Build(); + }); + services.AddSingleton(); + services.AddSingleton(serviceProvider => + { + return serviceProvider.GetService(); + }); + services.AddSingleton(serviceProvider => + { + var mqttClientService = serviceProvider.GetService(); + var mqttClientServiceProvider = new MqttClientServiceProvider(mqttClientService); + return mqttClientServiceProvider; + }); + return services; + } + + } +} diff --git a/MyCore/MyCore.csproj b/MyCore/MyCore.csproj index 36fe0cd..24be06f 100644 --- a/MyCore/MyCore.csproj +++ b/MyCore/MyCore.csproj @@ -26,7 +26,7 @@ - + diff --git a/MyCore/Services/Devices/DeviceService.cs b/MyCore/Services/Devices/DeviceService.cs index 00cfa33..96d581f 100644 --- a/MyCore/Services/Devices/DeviceService.cs +++ b/MyCore/Services/Devices/DeviceService.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Mvc; +using Mqtt.Client.AspNetCore.Services; using MyCore.Interfaces.DTO; using MyCore.Interfaces.Models; using MyCore.Services.MyControlPanel; @@ -115,11 +116,12 @@ namespace MyCore.Services.Devices try { + await MqttClientService.PublishMessage("test", "coucou test"); // TODO MQTT Connexion // TODO Server.. - MQTTService mQTTService = new MQTTService("192.168.31.140", "mqtt", "mqtt"); + //MQTTService mQTTService = new MQTTService("192.168.31.140", "mqtt", "mqtt"); - mQTTService.GetDevices(); + //mQTTService.GetDevices(); } catch (UnauthorizedAccessException ex) { diff --git a/MyCore/Startup.cs b/MyCore/Startup.cs index 2b49175..f3b4917 100644 --- a/MyCore/Startup.cs +++ b/MyCore/Startup.cs @@ -29,6 +29,12 @@ using NSwag.Generation.AspNetCore; using NSwag.Generation.Processors.Security; using MyCore.Framework.Business; using MyCore.Service.Services; +using MQTTnet; +using MQTTnet.AspNetCore; +using MQTTnet.AspNetCore.Extensions; +using MyCore.Service.Extensions; +using Mqtt.Client.AspNetCore.Services; +using Mqtt.Client.AspNetCore.Settings; namespace MyCore { @@ -47,10 +53,32 @@ namespace MyCore /*YeelightService yeelighService = new YeelightService(); yeelighService.GetDevices();*/ + MapConfiguration(); + } public IConfiguration Configuration { get; } + private void MapConfiguration() + { + MapBrokerHostSettings(); + MapClientSettings(); + } + + private void MapBrokerHostSettings() + { + BrokerHostSettings brokerHostSettings = new BrokerHostSettings(); + Configuration.GetSection(nameof(BrokerHostSettings)).Bind(brokerHostSettings); + AppSettingsProvider.BrokerHostSettings = brokerHostSettings; + } + + private void MapClientSettings() + { + ClientSettings clientSettings = new ClientSettings(); + Configuration.GetSection(nameof(ClientSettings)).Bind(clientSettings); + AppSettingsProvider.ClientSettings = clientSettings; + } + // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { @@ -160,23 +188,14 @@ namespace MyCore services.AddScoped(); services.AddScoped(typeof(ProfileLogic)); - // Add the service (test purpose) services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); - - services.AddScoped(); - - services.AddScoped(c => { - MQTTService mQTTService = new MQTTService("192.168.31.140", "mqtt", "mqtt"); - - mQTTService.GetDevices(); - return mQTTService; - }); + services.AddMqttClientHostedService(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. @@ -241,6 +260,7 @@ namespace MyCore config.GenerateEnumMappingDescription = true; } + private void HandleError(IApplicationBuilder error) { error.Run(async context => @@ -257,5 +277,7 @@ namespace MyCore } }); } + + } } diff --git a/MyCore/appsettings.json b/MyCore/appsettings.json index d151b6b..f80fe42 100644 --- a/MyCore/appsettings.json +++ b/MyCore/appsettings.json @@ -22,5 +22,15 @@ "Audience": "the client of your app", "IdType": "Name", "TokenExpiryInHours": 2 + }, + "BrokerHostSettings": { + "Host": "192.168.31.140", + "Port": 1883 + }, + + "ClientSettings": { + "Id": "5eb020f043ba8930506acbdd", + "UserName": "mqtt", + "Password": "mqtt" } }