2021-01-04 21:18:01 +01:00

324 lines
18 KiB
C#

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<List<DeviceDetailDTO>> 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<DeviceDetailDTO> createdDevice = new List<DeviceDetailDTO>();
try {
switch (provider.Type)
{
case "arlo":
List<ArloDevice> arloDevices = new ArloService(provider.Username, provider.Password).GetAllDevices();
createdDevice = CreateArloDevices(_DeviceDatabaseService, _ProviderDatabaseService, _LocationDatabaseService, userId, arloDevices, provider);
break;
case "meross":
List<MerossDevice> merossDevices = new MerossService(provider.Username, provider.Password).GetMerossDevices();
createdDevice = CreateMerossDevices(_DeviceDatabaseService, _ProviderDatabaseService, _LocationDatabaseService, userId, merossDevices, provider);
break;
case "yeelight":
List<YeelightAPI.Device> yeelightDevices = await new YeelightService().GetDevices();
createdDevice = CreateYeelightDevices(_DeviceDatabaseService, _ProviderDatabaseService, _LocationDatabaseService, userId, yeelightDevices, provider);
break;
case "zigbee2mqtt":
List<Zigbee2MqttDevice> 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<List<DeviceDetailDTO>> CreateFromZigbeeAsync(DeviceDatabaseService _DeviceDatabaseService, ProviderDatabaseService _ProviderDatabaseService, LocationDatabaseService _LocationDatabaseService, string userId, List<Zigbee2MqttDevice> zigbee2MqttDevices, Provider provider)
{
List<DeviceDetailDTO> createdZigbeeDevices = new List<DeviceDetailDTO>();
List<Device> 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<MeansOfCommunication>();
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<DeviceDetailDTO> CreateArloDevices(DeviceDatabaseService _DeviceDatabaseService, ProviderDatabaseService _ProviderDatabaseService, LocationDatabaseService _LocationDatabaseService, string userId, List<ArloDevice> arloDevices, Provider provider)
{
List<DeviceDetailDTO> createdArloDevices = new List<DeviceDetailDTO>();
List<Device> 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<string, object> properties = new Dictionary<string, object>();
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<MeansOfCommunication>();
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<DeviceDetailDTO> CreateMerossDevices(DeviceDatabaseService _DeviceDatabaseService, ProviderDatabaseService _ProviderDatabaseService, LocationDatabaseService _LocationDatabaseService, string userId, List<MerossDevice> merossDevices, Provider provider)
{
List<DeviceDetailDTO> createdMerossDevices = new List<DeviceDetailDTO>();
List<Device> 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<string, object> properties = new Dictionary<string, object>();
foreach (var property in meross.channels)
{
if (property.type != null)
properties.Add(property.devName, property.type);
}
// deviceDetailDTO.SupportedOperations = supportedOperationsDTO; TODO
deviceDetailDTO.MeansOfCommunications = new List<MeansOfCommunication>();
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<DeviceDetailDTO> CreateYeelightDevices(DeviceDatabaseService _DeviceDatabaseService, ProviderDatabaseService _ProviderDatabaseService, LocationDatabaseService _LocationDatabaseService, string userId, List<YeelightAPI.Device> yeelightDevices, Provider provider)
{
List<DeviceDetailDTO> createdYeelightDevices = new List<DeviceDetailDTO>();
List<Device> 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<string, object> properties = new Dictionary<string, object>();
foreach (var property in light.Properties)
{
properties.Add(property.Key, property.Value);
}
deviceDetailDTO.Properties = properties;
List<string> supportedOperationsDTO = new List<string>();
foreach (var supportedOperation in light.SupportedOperations)
{
supportedOperationsDTO.Add(supportedOperation.ToString());
}
deviceDetailDTO.SupportedOperations = supportedOperationsDTO;
deviceDetailDTO.MeansOfCommunications = new List<MeansOfCommunication>();
deviceDetailDTO.MeansOfCommunications.Add(MeansOfCommunication.Wifi);
deviceDetailDTO.CreatedDate = DateTime.Now;
deviceDetailDTO.UpdatedDate = DateTime.Now;
createdYeelightDevices.Add(CreateOrUpdate(_DeviceDatabaseService, _ProviderDatabaseService, _LocationDatabaseService, userId, deviceDetailDTO, true));
}
return createdYeelightDevices;
}
}
}