From 4191e6137b5ce41dd6b70244b37f8c636254704f Mon Sep 17 00:00:00 2001 From: Thomas Fransolet Date: Mon, 4 Jan 2021 21:18:01 +0100 Subject: [PATCH] Add Zigbee2Mqtt devices (WIP) => Type left --- MyCore.Interfaces/DTO/Common/DeviceType.cs | 7 +- .../DTO/MyControlPanel/DeviceDTO.cs | 7 ++ .../DTO/MyControlPanel/ProviderDTO.cs | 2 + .../Models/MyControlPanel/Database/Device.cs | 10 +++ .../MyControlPanel/Database/Provider.cs | 12 ++- .../Controllers/Devices/DeviceController.cs | 74 +----------------- MyCore/Extensions/MqttClientService.cs | 12 +++ MyCore/Services/Devices/DeviceService.cs | 77 ++++++++++++++----- .../MyControlPanel/ProviderService.cs | 12 +-- 9 files changed, 116 insertions(+), 97 deletions(-) diff --git a/MyCore.Interfaces/DTO/Common/DeviceType.cs b/MyCore.Interfaces/DTO/Common/DeviceType.cs index f207d9b..f78c791 100644 --- a/MyCore.Interfaces/DTO/Common/DeviceType.cs +++ b/MyCore.Interfaces/DTO/Common/DeviceType.cs @@ -10,11 +10,16 @@ namespace MyCore.Interfaces.DTO Sensor = 1, Actuator, Camera, + Switch, Light, Sound, Plug, Thermostat, Valve, - Gateway + Door, + Environment, + Motion, + Gateway, + Unknown } } diff --git a/MyCore.Interfaces/DTO/MyControlPanel/DeviceDTO.cs b/MyCore.Interfaces/DTO/MyControlPanel/DeviceDTO.cs index cd2bde8..49bb50b 100644 --- a/MyCore.Interfaces/DTO/MyControlPanel/DeviceDTO.cs +++ b/MyCore.Interfaces/DTO/MyControlPanel/DeviceDTO.cs @@ -11,6 +11,8 @@ namespace MyCore.Interfaces.DTO public string UserId { get; set; } + public string Description { get; set; } + public string Name { get; set; } public string Model { get; set; } @@ -43,6 +45,7 @@ namespace MyCore.Interfaces.DTO public string UserId { get; set; } public string Name { get; set; } + public string Description { get; set; } public string Model { get; set; } @@ -50,6 +53,8 @@ namespace MyCore.Interfaces.DTO public string FirmwareVersion { get; set; } + public string HardwareVersion { get; set; } + public int Port { get; set; } public ConnectionStatus ConnectionStatus { get; set; } @@ -82,6 +87,8 @@ namespace MyCore.Interfaces.DTO public string ProviderName { get; set; } + public string ManufacturerName { get; set; } + public List GroupIds { get; set; } public Dictionary Properties { get; set; } diff --git a/MyCore.Interfaces/DTO/MyControlPanel/ProviderDTO.cs b/MyCore.Interfaces/DTO/MyControlPanel/ProviderDTO.cs index 5f5c1e5..13cda7d 100644 --- a/MyCore.Interfaces/DTO/MyControlPanel/ProviderDTO.cs +++ b/MyCore.Interfaces/DTO/MyControlPanel/ProviderDTO.cs @@ -9,7 +9,9 @@ namespace MyCore.Interfaces.DTO { public string Id { get; set; } public string Name { get; set; } + public string Type { get; set; } public string UserId { get; set; } + public string Endpoint { get; set; } public string Username { get; set; } public string Password { get; set; } // TODO ENCRYPTED public string ApiKey { get; set; } // TODO ENCRYPTED diff --git a/MyCore.Interfaces/Models/MyControlPanel/Database/Device.cs b/MyCore.Interfaces/Models/MyControlPanel/Database/Device.cs index ba5c73c..4245c25 100644 --- a/MyCore.Interfaces/Models/MyControlPanel/Database/Device.cs +++ b/MyCore.Interfaces/Models/MyControlPanel/Database/Device.cs @@ -25,6 +25,9 @@ namespace MyCore.Interfaces.Models [BsonRequired] public string Name { get; set; } + [BsonElement("Description")] + public string Description { get; set; } + [BsonElement("Model")] [BsonRequired] public string Model { get; set; } @@ -37,6 +40,9 @@ namespace MyCore.Interfaces.Models [BsonRequired] public string FirmwareVersion { get; set; } + [BsonElement("HardwareVersion")] + public string HardwareVersion { get; set; } + [BsonElement("Status")] public bool Status { get; set; } @@ -80,6 +86,10 @@ namespace MyCore.Interfaces.Models [BsonRequired] public string ProviderId { get; set; } + [BsonElement("ManufacturerName")] + [BsonRequired] + public string ManufacturerName { get; set; } + [BsonElement("GroupIds")] public List GroupIds { get; set; } diff --git a/MyCore.Interfaces/Models/MyControlPanel/Database/Provider.cs b/MyCore.Interfaces/Models/MyControlPanel/Database/Provider.cs index e0a631f..592ad02 100644 --- a/MyCore.Interfaces/Models/MyControlPanel/Database/Provider.cs +++ b/MyCore.Interfaces/Models/MyControlPanel/Database/Provider.cs @@ -23,6 +23,10 @@ namespace MyCore.Interfaces.Models [BsonRequired] public string Name { get; set; } + [BsonElement("Type")] + [BsonRequired] + public string Type { get; set; } + [BsonElement("Username")] [BsonRequired] public string Username { get; set; } @@ -31,6 +35,10 @@ namespace MyCore.Interfaces.Models [BsonRequired] public string Password { get; set; } // TODO ENCRYPTED + [BsonElement("Endpoint")] + [BsonRequired] + public string Endpoint { get; set; } + [BsonElement("ApiKey")] public string ApiKey { get; set; } // TODO ENCRYPTED @@ -43,8 +51,10 @@ namespace MyCore.Interfaces.Models return new ProviderDTO() { Id = Id, - Name = Name, + Type = Type, + Name = Name, UserId = UserId, + Endpoint = Endpoint, /*Username = Username, Password = Password, ApiKey = ApiKey,*/ diff --git a/MyCore/Controllers/Devices/DeviceController.cs b/MyCore/Controllers/Devices/DeviceController.cs index 746a36d..f60a6c3 100644 --- a/MyCore/Controllers/Devices/DeviceController.cs +++ b/MyCore/Controllers/Devices/DeviceController.cs @@ -172,7 +172,7 @@ namespace MyCore.Controllers /// User Id [ProducesResponseType(typeof(List), 200)] [HttpGet("zigbee2Mqtt/{userId}")] - public async Task GetDevicesFromZigbee2Mqtt(string userId) + public ObjectResult GetDevicesFromZigbee2Mqtt(string userId) { try { @@ -183,33 +183,7 @@ namespace MyCore.Controllers throw new KeyNotFoundException("User not found"); // 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"); - } - }); + var devices = MqttClientService.devices; // Be carefull, we only got the exact result after each connection return new OkObjectResult(devices); } @@ -223,50 +197,6 @@ namespace MyCore.Controllers } } - /// - /// Create devices from provider - /// - /// User Id - [ProducesResponseType(typeof(List), 200)] - [HttpPost("fromZigbee2Mqtt/{userId}")] - public async Task CreateDevicesFromZigbee2Mqtt(string userId) - { - try - { - if (userId == null) - throw new InvalidOperationException("User not found"); - - 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(test); - } - catch (InvalidOperationException ex) - { - return new BadRequestObjectResult(ex.Message) { StatusCode = 400 }; - } - catch (Exception ex) - { - return new ObjectResult(ex.Message) { StatusCode = 500 }; - } - } - /// /// Update a device /// diff --git a/MyCore/Extensions/MqttClientService.cs b/MyCore/Extensions/MqttClientService.cs index f92383a..9f35888 100644 --- a/MyCore/Extensions/MqttClientService.cs +++ b/MyCore/Extensions/MqttClientService.cs @@ -138,5 +138,17 @@ namespace Mqtt.Client.AspNetCore.Services { return devices; } + + public static async Task> AskDevicesAsync() + { + await PublishMessage("zigbee2mqtt/bridge/config/devices/get", ""); + + // WARNING BAD CODE BELOW + while (devices.Count <= 0) { + // wait + } + + return devices; + } } } diff --git a/MyCore/Services/Devices/DeviceService.cs b/MyCore/Services/Devices/DeviceService.cs index bbc11a1..b5f85f3 100644 --- a/MyCore/Services/Devices/DeviceService.cs +++ b/MyCore/Services/Devices/DeviceService.cs @@ -76,26 +76,30 @@ namespace MyCore.Services.Devices public async static Task> CreateFromProvider(DeviceDatabaseService _DeviceDatabaseService, ProviderDatabaseService _ProviderDatabaseService, LocationDatabaseService _LocationDatabaseService, string userId, Provider provider) { - if (!ProviderService.IsProviderSupported(provider.Name)) + if (!ProviderService.IsProviderSupported(provider.Type)) throw new KeyNotFoundException("Provider is not yet supported"); List createdDevice = new List(); try { - switch (provider.Name) + switch (provider.Type) { - case "Arlo": + case "arlo": List arloDevices = new ArloService(provider.Username, provider.Password).GetAllDevices(); createdDevice = CreateArloDevices(_DeviceDatabaseService, _ProviderDatabaseService, _LocationDatabaseService, userId, arloDevices, provider); break; - case "Meross": + case "meross": List merossDevices = new MerossService(provider.Username, provider.Password).GetMerossDevices(); createdDevice = CreateMerossDevices(_DeviceDatabaseService, _ProviderDatabaseService, _LocationDatabaseService, userId, merossDevices, provider); break; - case "Yeelight": + case "yeelight": List yeelightDevices = await new YeelightService().GetDevices(); createdDevice = CreateYeelightDevices(_DeviceDatabaseService, _ProviderDatabaseService, _LocationDatabaseService, userId, yeelightDevices, provider); break; + case "zigbee2mqtt": + List zigbee2MqttDevices = MqttClientService.devices; + createdDevice = await CreateFromZigbeeAsync(_DeviceDatabaseService, _ProviderDatabaseService, _LocationDatabaseService, userId, zigbee2MqttDevices, provider); + break; } } catch (AuthenticationException ex) { @@ -110,25 +114,59 @@ namespace MyCore.Services.Devices return createdDevice; } - public async static Task> CreateFromZigbee(DeviceDatabaseService _DeviceDatabaseService, ProviderDatabaseService _ProviderDatabaseService, LocationDatabaseService _LocationDatabaseService, string userId) + public static async Task> CreateFromZigbeeAsync(DeviceDatabaseService _DeviceDatabaseService, ProviderDatabaseService _ProviderDatabaseService, LocationDatabaseService _LocationDatabaseService, string userId, List zigbee2MqttDevices, Provider provider) { - List createdDevice = new List(); + List createdZigbeeDevices = new List(); - try - { - await MqttClientService.PublishMessage("test", "coucou test"); - // TODO MQTT Connexion - // TODO Server.. - //MQTTService mQTTService = new MQTTService("192.168.31.140", "mqtt", "mqtt"); + List existingDevices = _DeviceDatabaseService.GetByprovider(provider.Id); - //mQTTService.GetDevices(); - } - catch (UnauthorizedAccessException ex) + if (zigbee2MqttDevices.Count <= 0) { - throw new UnauthorizedAccessException("Error connecting to mqtt server: " + ex.Message); + zigbee2MqttDevices = await MqttClientService.AskDevicesAsync(); } - return createdDevice; + zigbee2MqttDevices = zigbee2MqttDevices.Where(yd => !existingDevices.Select(ed => ed.ServiceIdentification).ToList().Contains(yd.ieeeAddr)).ToList(); + + foreach (var zigbee2MqttDevice in zigbee2MqttDevices) + { + DeviceDetailDTO deviceDetailDTO = new DeviceDetailDTO(); + deviceDetailDTO.Name = zigbee2MqttDevice.friendly_name; + deviceDetailDTO.Description = zigbee2MqttDevice.description; + deviceDetailDTO.ServiceIdentification = zigbee2MqttDevice.ieeeAddr; + deviceDetailDTO.ProviderId = provider.Id; + deviceDetailDTO.ProviderName = provider.Name; + + deviceDetailDTO.Model = zigbee2MqttDevice.model; // Will be the base to understand incoming messages ! + deviceDetailDTO.FirmwareVersion = zigbee2MqttDevice.softwareBuildID; + deviceDetailDTO.HardwareVersion = zigbee2MqttDevice.hardwareVersion.ToString(); + + + deviceDetailDTO.Type = DeviceType.Unknown; + + // TODO ! => switch case en fonction du model pour gestion des appareils compatibles + if (zigbee2MqttDevice.type == "Coordinator") deviceDetailDTO.Type = DeviceType.Gateway; + if (zigbee2MqttDevice.modelID.Contains("plug")) deviceDetailDTO.Type = DeviceType.Plug; + if (zigbee2MqttDevice.modelID.Contains("bulb")) deviceDetailDTO.Type = DeviceType.Light; + if (zigbee2MqttDevice.modelID.Contains("remote") || zigbee2MqttDevice.modelID.Contains("switch") || zigbee2MqttDevice.modelID.Contains("cube") || zigbee2MqttDevice.modelID.Contains("Sound Controller")) deviceDetailDTO.Type = DeviceType.Switch; + if (zigbee2MqttDevice.modelID.Contains("magnet")) deviceDetailDTO.Type = DeviceType.Door; + if (zigbee2MqttDevice.modelID.Contains("motion")) deviceDetailDTO.Type = DeviceType.Motion; + if (zigbee2MqttDevice.modelID.Contains("weather") || zigbee2MqttDevice.modelID.Contains("smoke") || zigbee2MqttDevice.modelID.Contains("wleak") || zigbee2MqttDevice.modelID.Contains("vibration")) deviceDetailDTO.Type = DeviceType.Environment; + + + deviceDetailDTO.Battery = zigbee2MqttDevice.powerSource.Contains("Battery"); + deviceDetailDTO.ManufacturerName = zigbee2MqttDevice.vendor; + deviceDetailDTO.MeansOfCommunications = new List(); + deviceDetailDTO.MeansOfCommunications.Add(MeansOfCommunication.Zigbee); + + deviceDetailDTO.CreatedDate = DateTime.Now; + deviceDetailDTO.UpdatedDate = DateTime.Now; + deviceDetailDTO.LastStateDate = new DateTime(zigbee2MqttDevice.lastSeen); + + createdZigbeeDevices.Add(CreateOrUpdate(_DeviceDatabaseService, _ProviderDatabaseService, _LocationDatabaseService, userId, deviceDetailDTO, true)); + } + + return createdZigbeeDevices; + } public static List CreateArloDevices(DeviceDatabaseService _DeviceDatabaseService, ProviderDatabaseService _ProviderDatabaseService, LocationDatabaseService _LocationDatabaseService, string userId, List arloDevices, Provider provider) @@ -145,6 +183,7 @@ namespace MyCore.Services.Devices deviceDetailDTO.Name = arlo.deviceName; deviceDetailDTO.ServiceIdentification = arlo.deviceId; deviceDetailDTO.ProviderId = provider.Id; + deviceDetailDTO.ProviderName = provider.Name; if (arlo.connectivity != null) { deviceDetailDTO.ConnectionStatus = arlo.connectivity.connected ? ConnectionStatus.Connected : ConnectionStatus.Unknown; @@ -199,6 +238,7 @@ namespace MyCore.Services.Devices deviceDetailDTO.Name = meross.devName; deviceDetailDTO.ServiceIdentification = meross.uuid; deviceDetailDTO.ProviderId = provider.Id; + deviceDetailDTO.ProviderName = provider.Name; deviceDetailDTO.ConnectionStatus = meross.onlineStatus == 1 ? ConnectionStatus.Connected : ConnectionStatus.Disconnected; // deviceDetailDTO.Status = meross. ? true : false; // TODO STATE deviceDetailDTO.Model = meross.deviceType; @@ -251,6 +291,7 @@ namespace MyCore.Services.Devices deviceDetailDTO.IpAddress = light.Hostname; deviceDetailDTO.ServiceIdentification = light.Id; deviceDetailDTO.ProviderId = provider.Id; + deviceDetailDTO.ProviderName = provider.Name; deviceDetailDTO.ConnectionStatus = ConnectionStatus.Connected; deviceDetailDTO.Status = false; deviceDetailDTO.Model = light.Model.ToString(); diff --git a/MyCore/Services/MyControlPanel/ProviderService.cs b/MyCore/Services/MyControlPanel/ProviderService.cs index ac39a9d..341f903 100644 --- a/MyCore/Services/MyControlPanel/ProviderService.cs +++ b/MyCore/Services/MyControlPanel/ProviderService.cs @@ -11,10 +11,10 @@ namespace MyCore.Services.MyControlPanel public class ProviderService { static List supportedProviders = new List() { - "Arlo", - "Meross", - "Yeelight", - "ZigBee" + "arlo", + "meross", + "yeelight", + "zigbee2mqtt" }; public static bool IsExist(ProviderDatabaseService _ProviderDatabaseService, string userId, string providerId) @@ -37,10 +37,12 @@ namespace MyCore.Services.MyControlPanel provider = _ProviderDatabaseService.GetById(userId, providerDTO.Id); } - if (!IsProviderSupported(providerDTO.Name)) + if (!IsProviderSupported(providerDTO.Type)) throw new KeyNotFoundException("Provider is not yet supported"); + provider.Type = providerDTO.Type; provider.Name = providerDTO.Name; + provider.Endpoint = providerDTO.Endpoint; provider.UserId = providerDTO.UserId; provider.Username = providerDTO.Username; provider.Password = providerDTO.Password;