Mqtt as a service + get all devices from zigbee2mqtt + test zigbee publish in controller

This commit is contained in:
Thomas Fransolet 2021-01-02 00:48:50 +01:00
parent c92db12495
commit 1cc12876f7
15 changed files with 362 additions and 17 deletions

View File

@ -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
/// <summary>
/// User Information
/// </summary>
public class UserInfo //: IAuthenticationUser // TODO !
public class UserInfo
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]

View File

@ -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
}
}
/// <summary>
/// Get all zigbee2Mqtt devices
/// </summary>
/// <param name="userId">User Id</param>
[ProducesResponseType(typeof(List<DeviceDetailDTO>), 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 };
}
}
/// <summary>
/// Create devices from provider
/// </summary>
@ -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<DeviceDetailDTO> devicesCreated = await DeviceService.CreateFromZigbee(this._DeviceDatabaseService, this._ProviderDatabaseService, this._LocationDatabaseService, userId);
return new OkObjectResult(devicesCreated);
return new OkObjectResult(test);
}
catch (InvalidOperationException ex)
{

View File

@ -0,0 +1,8 @@
namespace Mqtt.Client.AspNetCore.Settings
{
public class AppSettingsProvider
{
public static BrokerHostSettings BrokerHostSettings;
public static ClientSettings ClientSettings;
}
}

View File

@ -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;
}
}
}

View File

@ -0,0 +1,8 @@
namespace Mqtt.Client.AspNetCore.Settings
{
public class BrokerHostSettings
{
public string Host { set; get; }
public int Port { set; get; }
}
}

View File

@ -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; }
}
}

View File

@ -0,0 +1,11 @@
namespace Mqtt.Client.AspNetCore.Services
{
public class ExtarnalService
{
private readonly IMqttClientService mqttClientService;
public ExtarnalService(MqttClientServiceProvider provider)
{
mqttClientService = provider.MqttClientService;
}
}
}

View File

@ -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
{
}
}

View File

@ -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<Zigbee2MqttDevice> devices = new List<Zigbee2MqttDevice>();
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<List<Zigbee2MqttDevice>>(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<Zigbee2MqttDevice> GetDevices()
{
return devices;
}
}
}

View File

@ -0,0 +1,12 @@
namespace Mqtt.Client.AspNetCore.Services
{
public class MqttClientServiceProvider
{
public readonly IMqttClientService MqttClientService;
public MqttClientServiceProvider(IMqttClientService mqttClientService)
{
MqttClientService = mqttClientService;
}
}
}

View File

@ -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<AspCoreMqttClientOptionBuilder> configure)
{
services.AddSingleton<IMqttClientOptions>(serviceProvider =>
{
var optionBuilder = new AspCoreMqttClientOptionBuilder(serviceProvider);
configure(optionBuilder);
return optionBuilder.Build();
});
services.AddSingleton<MqttClientService>();
services.AddSingleton<IHostedService>(serviceProvider =>
{
return serviceProvider.GetService<MqttClientService>();
});
services.AddSingleton<MqttClientServiceProvider>(serviceProvider =>
{
var mqttClientService = serviceProvider.GetService<MqttClientService>();
var mqttClientServiceProvider = new MqttClientServiceProvider(mqttClientService);
return mqttClientServiceProvider;
});
return services;
}
}
}

View File

@ -26,7 +26,7 @@
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.0.2105168" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.1.1" />
<PackageReference Include="MongoDB.Driver" Version="2.11.5" />
<PackageReference Include="MQTTnet" Version="3.0.8" />
<PackageReference Include="MQTTnet.AspNetCore" Version="3.0.13" />
<PackageReference Include="NSwag.AspNetCore" Version="13.9.2" />
<PackageReference Include="ServiceStack.Client" Version="5.8.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="4.0.1" />

View File

@ -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)
{

View File

@ -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<TokensService>();
services.AddScoped(typeof(ProfileLogic));
// Add the service (test purpose)
services.AddScoped<BookService>();
services.AddScoped<IoTDeviceService>();
services.AddScoped<UserDatabaseService>();
services.AddScoped<ProviderDatabaseService>();
services.AddScoped<DeviceDatabaseService>();
services.AddScoped<LocationDatabaseService>();
services.AddScoped<ScreenDeviceDatabaseService>();
services.AddScoped<MQTTService>(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
}
});
}
}
}

View File

@ -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"
}
}