using Microsoft.AspNetCore.Mvc; using Mqtt.Client.AspNetCore.Services; using MyCore.Interfaces.DTO; using MyCore.Interfaces.Models; using MyCore.Services.MyControlPanel; using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Security.Authentication; using System.Threading.Tasks; namespace MyCore.Services.Devices { public class DeviceService { public static DeviceDetailDTO CreateOrUpdate(DeviceDatabaseService _DeviceDatabaseService, ProviderDatabaseService _ProviderDatabaseService, LocationDatabaseService _LocationDatabaseService, string userId, DeviceDetailDTO deviceDetailDTO, bool create) { Device device; if (create) device = new Device(); else { device = _DeviceDatabaseService.GetById(deviceDetailDTO.Id); } if (_DeviceDatabaseService.IsAlreadyHere(userId, deviceDetailDTO.ServiceIdentification, deviceDetailDTO.Model) && create) { return null; } device.UserId = userId; device.Name = deviceDetailDTO.Name; if (_ProviderDatabaseService.IsExist(deviceDetailDTO.ProviderId)) device.ProviderId = deviceDetailDTO.ProviderId; else throw new KeyNotFoundException("Provider does not exist"); if (device.LocationId == null || _LocationDatabaseService.IsExist(deviceDetailDTO.LocationId)) device.LocationId = deviceDetailDTO.LocationId; else throw new KeyNotFoundException("Location does not exist"); device.Port = deviceDetailDTO.Port; device.Model = deviceDetailDTO.Model; device.Type = deviceDetailDTO.Type; device.FirmwareVersion = deviceDetailDTO.FirmwareVersion; device.Status = deviceDetailDTO.Status; if (create) device.ConnectionStatus = ConnectionStatus.Unknown; else device.ConnectionStatus = deviceDetailDTO.ConnectionStatus; device.Status = deviceDetailDTO.Status; device.LocationId = deviceDetailDTO.LocationId; device.CreatedDate = DateTime.Now; device.UpdatedDate = DateTime.Now; device.MeansOfCommunications = deviceDetailDTO.MeansOfCommunications; device.IpAddress = deviceDetailDTO.IpAddress; device.ServiceIdentification = deviceDetailDTO.ServiceIdentification; device.Battery = deviceDetailDTO.Battery; device.BatteryStatus = deviceDetailDTO.BatteryStatus; device.GroupIds = deviceDetailDTO.GroupIds; // Todo structure Properties device.Properties = deviceDetailDTO.Properties; // Todo structure SupportedOperations device.SupportedOperations = deviceDetailDTO.SupportedOperations; if (create) return _DeviceDatabaseService.Create(device).ToDTO(); else return _DeviceDatabaseService.Update(device.Id, device).ToDTO(); } public async static Task> CreateFromProvider(DeviceDatabaseService _DeviceDatabaseService, ProviderDatabaseService _ProviderDatabaseService, LocationDatabaseService _LocationDatabaseService, string userId, Provider provider) { if (!ProviderService.IsProviderSupported(provider.Type)) throw new KeyNotFoundException("Provider is not yet supported"); List createdDevice = new List(); try { switch (provider.Type) { case "arlo": List arloDevices = new ArloService(provider.Username, provider.Password).GetAllDevices(); createdDevice = CreateArloDevices(_DeviceDatabaseService, _ProviderDatabaseService, _LocationDatabaseService, userId, arloDevices, provider); break; case "meross": List merossDevices = new MerossService(provider.Username, provider.Password).GetMerossDevices(); createdDevice = CreateMerossDevices(_DeviceDatabaseService, _ProviderDatabaseService, _LocationDatabaseService, userId, merossDevices, provider); break; 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) { throw new AuthenticationException("Bad username or password for service " + provider.Name + " ex: " + ex.Message); } catch (HttpRequestException ex) { throw new HttpRequestException("Error retrieving devices for " + provider.Name + " ex: " + ex.Message); } catch (Exception ex) { } return createdDevice; } public static async Task> CreateFromZigbeeAsync(DeviceDatabaseService _DeviceDatabaseService, ProviderDatabaseService _ProviderDatabaseService, LocationDatabaseService _LocationDatabaseService, string userId, List zigbee2MqttDevices, Provider provider) { List createdZigbeeDevices = new List(); List existingDevices = _DeviceDatabaseService.GetByprovider(provider.Id); if (zigbee2MqttDevices.Count <= 0) { zigbee2MqttDevices = await MqttClientService.AskDevicesAsync(); } 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) { List createdArloDevices = new List(); List existingDevices = _DeviceDatabaseService.GetByprovider(provider.Id); arloDevices = arloDevices.Where(yd => !existingDevices.Select(ed => ed.ServiceIdentification).ToList().Contains(yd.deviceId)).ToList(); foreach (var arlo in arloDevices) { DeviceDetailDTO deviceDetailDTO = new DeviceDetailDTO(); 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; deviceDetailDTO.Status = arlo.connectivity.connected ? true : false; // TODO STATE } else deviceDetailDTO.ConnectionStatus = ConnectionStatus.Unknown; deviceDetailDTO.Model = arlo.modelId; deviceDetailDTO.FirmwareVersion = arlo.interfaceVersion; // TODO switch (arlo.deviceType) { case "camera": deviceDetailDTO.Type = DeviceType.Camera; Dictionary properties = new Dictionary(); properties.Add("lastImageUploaded", arlo.lastImageUploaded); properties.Add("presignedLastImageUrl", arlo.presignedLastImageUrl); properties.Add("presignedFullFrameSnapshotUrl", arlo.presignedFullFrameSnapshotUrl); properties.Add("presignedSnapshotUrl", arlo.presignedSnapshotUrl); deviceDetailDTO.Properties = properties; break; case "siren": deviceDetailDTO.Type = DeviceType.Sound; break; case "basestation": deviceDetailDTO.Type = DeviceType.Gateway; break; } deviceDetailDTO.MeansOfCommunications = new List(); deviceDetailDTO.MeansOfCommunications.Add(MeansOfCommunication.Wifi); // To check deviceDetailDTO.CreatedDate = DateTime.Now; deviceDetailDTO.UpdatedDate = DateTime.Now; createdArloDevices.Add(CreateOrUpdate(_DeviceDatabaseService, _ProviderDatabaseService, _LocationDatabaseService, userId, deviceDetailDTO, true)); } return createdArloDevices; } public static List CreateMerossDevices(DeviceDatabaseService _DeviceDatabaseService, ProviderDatabaseService _ProviderDatabaseService, LocationDatabaseService _LocationDatabaseService, string userId, List merossDevices, Provider provider) { List createdMerossDevices = new List(); List existingDevices = _DeviceDatabaseService.GetByprovider(provider.Id); merossDevices = merossDevices.Where(yd => !existingDevices.Select(ed => ed.ServiceIdentification).ToList().Contains(yd.uuid)).ToList(); foreach (var meross in merossDevices) { DeviceDetailDTO deviceDetailDTO = new DeviceDetailDTO(); 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; switch (deviceDetailDTO.Model) // TODO { case "mss425f": deviceDetailDTO.Type = DeviceType.Plug; break; case "mss310": deviceDetailDTO.Type = DeviceType.Actuator; break; case "msh300": deviceDetailDTO.Type = DeviceType.Gateway; break; default: deviceDetailDTO.Type = DeviceType.Actuator; break; } deviceDetailDTO.FirmwareVersion = meross.firmwareVersion; // TODO Dictionary properties = new Dictionary(); foreach (var property in meross.channels) { if (property.type != null) properties.Add(property.devName, property.type); } // deviceDetailDTO.SupportedOperations = supportedOperationsDTO; TODO deviceDetailDTO.MeansOfCommunications = new List(); deviceDetailDTO.MeansOfCommunications.Add(MeansOfCommunication.Wifi); // TO CHECK deviceDetailDTO.CreatedDate = DateTime.Now; deviceDetailDTO.UpdatedDate = DateTime.Now; createdMerossDevices.Add(CreateOrUpdate(_DeviceDatabaseService, _ProviderDatabaseService, _LocationDatabaseService, userId, deviceDetailDTO, true)); } return createdMerossDevices; } public static List CreateYeelightDevices(DeviceDatabaseService _DeviceDatabaseService, ProviderDatabaseService _ProviderDatabaseService, LocationDatabaseService _LocationDatabaseService, string userId, List yeelightDevices, Provider provider) { List createdYeelightDevices = new List(); List existingDevices = _DeviceDatabaseService.GetByprovider(provider.Id); yeelightDevices = yeelightDevices.Where(yd => !existingDevices.Select(ed => ed.ServiceIdentification).ToList().Contains(yd.Id)).ToList(); foreach (var light in yeelightDevices) { DeviceDetailDTO deviceDetailDTO = new DeviceDetailDTO(); deviceDetailDTO.Name = light.Name; 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(); deviceDetailDTO.Type = DeviceType.Light; // TO CHECK deviceDetailDTO.Port = light.Port; deviceDetailDTO.FirmwareVersion = light.FirmwareVersion; Dictionary properties = new Dictionary(); foreach (var property in light.Properties) { properties.Add(property.Key, property.Value); } deviceDetailDTO.Properties = properties; List supportedOperationsDTO = new List(); foreach (var supportedOperation in light.SupportedOperations) { supportedOperationsDTO.Add(supportedOperation.ToString()); } deviceDetailDTO.SupportedOperations = supportedOperationsDTO; deviceDetailDTO.MeansOfCommunications = new List(); deviceDetailDTO.MeansOfCommunications.Add(MeansOfCommunication.Wifi); deviceDetailDTO.CreatedDate = DateTime.Now; deviceDetailDTO.UpdatedDate = DateTime.Now; createdYeelightDevices.Add(CreateOrUpdate(_DeviceDatabaseService, _ProviderDatabaseService, _LocationDatabaseService, userId, deviceDetailDTO, true)); } return createdYeelightDevices; } } }