2023-08-11 16:50:41 +02:00

920 lines
50 KiB
C#

using DevExpress.Data.Mask;
using Microsoft.AspNetCore.Mvc;
using Mqtt.Client.AspNetCore.Services;
using MyCore.Interfaces.DTO;
using MyCore.Interfaces.Models;
using MyCore.Interfaces.Models.MyControlPanel;
using MyCore.Service.Services.Devices.SupportedDevices;
using MyCore.Services.MyControlPanel;
using Newtonsoft.Json;
using Swashbuckle.AspNetCore.Swagger;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Net.Http;
using System.Security.Authentication;
using System.Security.Claims;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace MyCore.Services.Devices
{
public class DeviceService
{
static List<SupportedDevice> supportedDevices = new List<SupportedDevice>() {
new SupportedDevice { Manufacturer = "Aqara", Model = "RTCGQ11LM", Description = "Aqara human body movement and illuminance sensor", DeviceType = DeviceType.Motion, IsIlluminance = true, IsOccupation = true, IsLinkQuality = true},
new SupportedDevice { Manufacturer = "Aqara", Model = "DJT11LM", Description = "Aqara vibration sensor", DeviceType = DeviceType.Environment, IsVibration = true, IsLinkQuality = true },
new SupportedDevice { Manufacturer = "Aqara", Model = "SJCGQ11LM", Description = "Aqara water leak sensor", DeviceType = DeviceType.Environment, IsWaterLeak = true, IsLinkQuality = true },
new SupportedDevice { Manufacturer = "Aqara", Model = "WSDCGQ11LM", Description = "Aqara temperature, humidity and pressure sensor", DeviceType = DeviceType.Environment, IsTemperature = true, IsHumidity = true, IsPressure = true, IsLinkQuality = true },
new SupportedDevice { Manufacturer = "Xiaomi", Model = "WXKG01LM", Description = "MiJia wireless switch", DeviceType = DeviceType.Switch, IsAction = true, IsLinkQuality = true },
new SupportedDevice { Manufacturer = "Xiaomi", Model = "MFKZQ01LM", Description = "Mi/Aqara smart home cube", DeviceType = DeviceType.Switch, IsAction = true, IsLinkQuality = true },
new SupportedDevice { Manufacturer = "Xiaomi", Model = "MCCGQ01LM", Description = "MiJia door & window contact sensor", DeviceType = DeviceType.Door, IsContact = true, IsLinkQuality = true },
new SupportedDevice { Manufacturer = "Xiaomi", Model = "JTYJ-GD-01LM/BW", Description = "MiJia Honeywell smoke detector", DeviceType = DeviceType.Environment, IsSmoke = true, IsLinkQuality = true },
new SupportedDevice { Manufacturer = "Xiaomi", Model = "ZNCZ04LM", Description = "Mi power plug ZigBee EU", DeviceType = DeviceType.Plug, IsCurrentPower = true, IsConsumption = true, IsTemperature = true, IsVoltage = true, IsLinkQuality = true },
new SupportedDevice { Manufacturer = "Ikea", Model = "E1744", Description = "SYMFONISK Sound Controller", DeviceType = DeviceType.Switch, IsAction = true, IsLinkQuality = true },
new SupportedDevice { Manufacturer = "Ikea", Model = "LED1836G9", Description = "TRADFRI LED bulb E26/E27 806 lumen, dimmable, warm white", DeviceType = DeviceType.Light, IsState = true, IsBrightness = true, IsLinkQuality = true },
new SupportedDevice { Manufacturer = "Ikea", Model = "LED1842G3", Description = "TRADFRI LED bulb E27 WW clear 250 lumen, dimmable", DeviceType = DeviceType.Light, IsState = true, IsBrightness = true, IsLinkQuality = true },
new SupportedDevice { Manufacturer = "Ikea", Model = "LED1837R5", Description = "TRADFRI LED bulb GU10 400 lumen, dimmable", DeviceType = DeviceType.Light, IsState = true, IsBrightness = true, IsLinkQuality = true },
new SupportedDevice { Manufacturer = "Ikea", Model = "E1743", Description = "TRADFRI ON/OFF switch", DeviceType = DeviceType.Switch, IsAction = true, IsLinkQuality = true },
new SupportedDevice { Manufacturer = "Ikea", Model = "E1524/E1810", Description = "TRADFRI remote control", DeviceType = DeviceType.Switch, IsAction = true, IsLinkQuality = true },
new SupportedDevice { Manufacturer = "Ikea", Model = "LED1924G9", Description = "TRADFRI bulb E26/E27 CWS 800/806 lumen, dimmable, color, opal white", DeviceType = DeviceType.Light, IsState = true, IsBrightness = true, IsColorTemp = true, IsColorXY = true, IsLinkQuality = true },
new SupportedDevice { Manufacturer = "Ikea", Model = "E2007", Description = "STARKVIND air purifier", DeviceType = DeviceType.Environment, IsAirQuality = true, IsFanMode = true, IsFanSpeed = true, IsLinkQuality = true },
new SupportedDevice { Manufacturer = "Ikea", Model = "ICPSHC24-10EU-IL-1", Description = "TRADFRI driver for wireless control (10 watt)", DeviceType = DeviceType.Light, IsLinkQuality = true },
new SupportedDevice { Manufacturer = "Ikea", Model = "ICPSHC24-30EU-IL-1", Description = "TRADFRI driver for wireless control (30 watt)", DeviceType = DeviceType.Light, IsLinkQuality = true },
new SupportedDevice { Manufacturer = "Ikea", Model = "E1812", Description = "TRADFRI shortcut button", DeviceType = DeviceType.Switch, IsAction = true, IsLinkQuality = true },
new SupportedDevice { Manufacturer = "Ikea", Model = "E1603/E1702/E1708", Description = "TRADFRI control outlet", DeviceType = DeviceType.Switch, IsState = true, IsLinkQuality = true }, // TODO update to plug
new SupportedDevice { Manufacturer = "SONOFF", Model = "BASICZBR3", Description = "Zigbee smart switch", DeviceType = DeviceType.Plug, IsState = true, IsLinkQuality = true },
new SupportedDevice { Manufacturer = "Philips", Model = "8718696743133", Description = "Hue tap", DeviceType = DeviceType.Switch, IsAction = true, IsLinkQuality = true },
new SupportedDevice { Manufacturer = "Neo", Model = "NAS-AB02B0", Description = "Temperature & humidity sensor and alarm", DeviceType = DeviceType.Sound, IsHumidity = true, IsTemperature = true, IsAlarm = true, IsLinkQuality = true },
new SupportedDevice { Manufacturer = "TuYa", Model = "TS0201", Description = "Temperature & humidity sensor with display", DeviceType = DeviceType.Environment, IsHumidity = true, IsTemperature = true, IsLinkQuality = true },
new SupportedDevice { Manufacturer = "TuYa", Model = "LCZ030", Description = "Temperature & humidity & illuminance sensor with display", DeviceType = DeviceType.Environment, IsHumidity = true, IsTemperature = true, IsIlluminance = true, IsLinkQuality = true },
};
public static DeviceDetailDTO CreateOrUpdate(DeviceDatabaseService _DeviceDatabaseService, ProviderDatabaseService _ProviderDatabaseService, RoomDatabaseService _RoomDatabaseService, string homeId, DeviceDetailDTO deviceDetailDTO, bool create, bool isZigbee = false)
{
Device device;
if (isZigbee)
{
device = _DeviceDatabaseService.GetByServiceIdentification(deviceDetailDTO.ServiceIdentification);
if (device == null)
device = new Device();
}
else {
if (create)
device = new Device();
else
{
device = _DeviceDatabaseService.GetById(deviceDetailDTO.Id);
}
}
/*// What's the purpose here ?
if (_DeviceDatabaseService.IsAlreadyHere(homeId, deviceDetailDTO.ServiceIdentification, deviceDetailDTO.Model) && create)
{
return null;
}*/
device.HomeId = homeId;
if (create) {
device.Name = deviceDetailDTO.Name;
}
device.Description = deviceDetailDTO.Description;
device.ManufacturerName = deviceDetailDTO.ManufacturerName;
if (_ProviderDatabaseService.IsExist(deviceDetailDTO.ProviderId))
device.ProviderId = deviceDetailDTO.ProviderId;
else
throw new KeyNotFoundException("Provider does not exist");
if (device.RoomId == null || _RoomDatabaseService.IsExist(deviceDetailDTO.RoomId))
device.RoomId = deviceDetailDTO.RoomId;
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.HardwareVersion = deviceDetailDTO.HardwareVersion;
if (create)
device.ConnectionStatus = ConnectionStatus.Unknown;
else
device.ConnectionStatus = deviceDetailDTO.ConnectionStatus;
device.RoomId = deviceDetailDTO.RoomId;
if (create)
{
device.CreatedDate = DateTime.Now;
}
else {
device.UpdatedDate = DateTime.Now;
device.LastMessage = deviceDetailDTO.LastMessage;
device.LastMessageDate = deviceDetailDTO.LastMessageDate;
}
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;
// TODO CHECK HERE IF NOT ERASING DATA .. on zigbee connection
device.IsContact = deviceDetailDTO.IsContact;
device.Contact = deviceDetailDTO.Contact;
device.IsIlluminance = deviceDetailDTO.IsIlluminance;
device.Illuminance = deviceDetailDTO.Illuminance != null ? deviceDetailDTO.Illuminance.Value : 0;
device.IsBrightness = deviceDetailDTO.IsBrightness;
device.Brightness = deviceDetailDTO.Brightness;
device.IsState = deviceDetailDTO.IsState;
device.State = deviceDetailDTO.State;
device.IsColorTemp = deviceDetailDTO.IsColorTemp;
device.ColorTemp = deviceDetailDTO.ColorTemp;
device.IsColorXY = deviceDetailDTO.IsColorXY;
device.ColorX = deviceDetailDTO.ColorX;
device.ColorY = deviceDetailDTO.ColorY;
device.IsOccupation = deviceDetailDTO.IsOccupation;
device.Occupation = deviceDetailDTO.Occupation;
device.IsAlarm = deviceDetailDTO.IsAlarm;
device.Alarm = deviceDetailDTO.Alarm;
device.IsTemperature = deviceDetailDTO.IsTemperature;
device.Temperature = deviceDetailDTO.Temperature != null ? deviceDetailDTO.Temperature.Value : 0;
device.IsHumidity = deviceDetailDTO.IsHumidity;
device.Humidity = deviceDetailDTO.Humidity != null ? deviceDetailDTO.Humidity.Value : 0;
device.IsPressure = deviceDetailDTO.IsPressure;
device.Pressure = deviceDetailDTO.Pressure != null ? deviceDetailDTO.Pressure.Value : 0;
device.IsConsumption = deviceDetailDTO.IsConsumption;
device.Consumption = deviceDetailDTO.Consumption;
device.IsCurrentPower = deviceDetailDTO.IsCurrentPower;
device.CurrentPower = deviceDetailDTO.CurrentPower;
device.IsVoltage = deviceDetailDTO.IsVoltage;
device.Voltage = deviceDetailDTO.Voltage;
device.IsLinkQuality = deviceDetailDTO.IsLinkQuality;
device.LinkQuality = deviceDetailDTO.LinkQuality;
device.IsCO2 = deviceDetailDTO.IsCO2;
device.CO2 = deviceDetailDTO.CO2;
device.IsNoise = deviceDetailDTO.IsNoise;
device.Noise = deviceDetailDTO.Noise;
if (deviceDetailDTO.SupportedOperations != null)
{
foreach (var supportedOperation in deviceDetailDTO.SupportedOperations)
{
var supportedOperationDeserialized = JsonConvert.DeserializeObject<Zigbee2MqttOperations>(supportedOperation);
device = UpdateDeviceCapabilities(device, supportedOperationDeserialized);
}
}
if (create)
return _DeviceDatabaseService.Create(device).ToDTO();
else
return _DeviceDatabaseService.Update(device).ToDTO();
}
public async static Task<Dictionary<string, List<DeviceDetailDTO>>> CreateFromProvider(DeviceDatabaseService _DeviceDatabaseService, ProviderDatabaseService _ProviderDatabaseService, RoomDatabaseService _RoomDatabaseService, string homeId, Provider provider)
{
Dictionary<string, List<DeviceDetailDTO>> devices = new Dictionary<string, List<DeviceDetailDTO>>();
try {
switch (provider.Type)
{
case ProviderType.arlo:
List<ArloDevice> arloDevices = new ArloService(provider.Username, provider.Password).GetAllDevices();
devices = CreateArloDevices(_DeviceDatabaseService, _ProviderDatabaseService, _RoomDatabaseService, homeId, arloDevices, provider);
break;
case ProviderType.meross:
List<MerossDevice> merossDevices = MqttClientMerossService.GetMerossDevices(); // TO TEST IF IT WORKS
devices = CreateMerossDevices(_DeviceDatabaseService, _ProviderDatabaseService, _RoomDatabaseService, homeId, merossDevices, provider);
break;
case ProviderType.yeelight:
List<YeelightAPI.Device> yeelightDevices = await YeelightService.GetDevices();
devices = CreateYeelightDevices(_DeviceDatabaseService, _ProviderDatabaseService, _RoomDatabaseService, homeId, yeelightDevices, provider);
break;
case ProviderType.netatmo:
NetatmoService netatmoService = new NetatmoService(provider.Username, provider.Password, provider.Value, provider.ValueRefresh, provider, _ProviderDatabaseService);
List<NetatmoHome> netatmoHomes = netatmoService.GetHomeData();
List<NetatmoCoachDevice> netatmoCoachDevices = netatmoService.GetHomeCoachsData();
devices = CreateOrUpdateNetatmoDevices(_DeviceDatabaseService, _ProviderDatabaseService, _RoomDatabaseService, homeId, netatmoHomes, netatmoCoachDevices, provider);
break;
case ProviderType.zigbee2mqtt:
if (MqttClientService.devices.Count > 0)
{
// Simple list mode
List<Zigbee2MqttDeviceConfig> zigbee2MqttDevices = MqttClientService.devices;
devices = await CreateFromZigbeeAsync(_DeviceDatabaseService, _ProviderDatabaseService, _RoomDatabaseService, homeId, zigbee2MqttDevices, provider);
}
if (MqttClientService.devicesNew.Count > 0)
{
// Complex list mode
List<Zigbee2MqttDevice> zigbee2MqttDevices = MqttClientService.devicesNew;
devices = await UpdateFromZigbeeAsync(_DeviceDatabaseService, _ProviderDatabaseService, _RoomDatabaseService, homeId, 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 devices;
}
// Old way
/*public static async Task<Dictionary<string, List<DeviceDetailDTO>>> CreateFromZigbeeAsync(DeviceDatabaseService _DeviceDatabaseService, ProviderDatabaseService _ProviderDatabaseService, LocationDatabaseService _LocationDatabaseService, string homeId, List<Zigbee2MqttDevice> zigbee2MqttDevices, Provider provider)
{
List<DeviceDetailDTO> createdZigbeeDevices = new List<DeviceDetailDTO>();
List<DeviceDetailDTO> notSupportedZigbeeDevices = new List<DeviceDetailDTO>();
List<Device> existingDevices = _DeviceDatabaseService.GetByProviderId(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.type == "Coordinator" ? "Coordinator" : zigbee2MqttDevice.model; // Is the base to understand incoming messages !
deviceDetailDTO.FirmwareVersion = zigbee2MqttDevice.softwareBuildID;
deviceDetailDTO.HardwareVersion = zigbee2MqttDevice.hardwareVersion.ToString();
deviceDetailDTO.Battery = zigbee2MqttDevice.powerSource == null ? false : zigbee2MqttDevice.powerSource.Contains("Battery");
deviceDetailDTO.ManufacturerName = zigbee2MqttDevice.vendor == null ? provider.Type : zigbee2MqttDevice.vendor.ToLower();
deviceDetailDTO.MeansOfCommunications = new List<MeansOfCommunication>();
deviceDetailDTO.MeansOfCommunications.Add(MeansOfCommunication.Zigbee);
deviceDetailDTO.CreatedDate = DateTime.Now;
deviceDetailDTO.UpdatedDate = DateTime.Now;
deviceDetailDTO.LastStateDate = new DateTime(zigbee2MqttDevice.lastSeen);
deviceDetailDTO.Type = zigbee2MqttDevice.type == "Coordinator" ? DeviceType.Gateway : GetDeviceTypeFromZigbeeModel(zigbee2MqttDevice.model);
if (deviceDetailDTO.Type != DeviceType.Unknown)
{
// Supoorted device !
createdZigbeeDevices.Add(CreateOrUpdate(_DeviceDatabaseService, _ProviderDatabaseService, _LocationDatabaseService, homeId, deviceDetailDTO, true));
}
else {
// Not yet supported !
notSupportedZigbeeDevices.Add(deviceDetailDTO);
}
}
return new Dictionary<string, List<DeviceDetailDTO>>() {
{ "createdDevices", createdZigbeeDevices },
{ "notSupportedDevices", notSupportedZigbeeDevices }
};
}*/
public static async Task<Dictionary<string, List<DeviceDetailDTO>>> CreateFromZigbeeAsync(DeviceDatabaseService _DeviceDatabaseService, ProviderDatabaseService _ProviderDatabaseService, RoomDatabaseService _RoomDatabaseService, string homeId, List<Zigbee2MqttDeviceConfig> zigbee2MqttDevices, Provider provider)
{
List<DeviceDetailDTO> createdZigbeeDevices = new List<DeviceDetailDTO>();
List<DeviceDetailDTO> notSupportedZigbeeDevices = new List<DeviceDetailDTO>();
List<Device> existingDevices = _DeviceDatabaseService.GetByProviderId(provider.Id);
// Not necessarry
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.ServiceIdentification = zigbee2MqttDevice.ieeeAddr;
deviceDetailDTO.ProviderId = provider.Id;
deviceDetailDTO.ProviderName = provider.Name;
deviceDetailDTO.Description = zigbee2MqttDevice.type == "Coordinator" ? "Coordinator" : zigbee2MqttDevice.description;
deviceDetailDTO.Model = zigbee2MqttDevice.type == "Coordinator" ? "Coordinator" : zigbee2MqttDevice.model; // Is the base to understand incoming messages !
//deviceDetailDTO.FirmwareVersion = zigbee2MqttDevice.software_build_id;
deviceDetailDTO.Battery = zigbee2MqttDevice.powerSource == null ? false : zigbee2MqttDevice.powerSource.Contains("Battery");
deviceDetailDTO.ManufacturerName = zigbee2MqttDevice.vendor == null ? provider.Type.ToString() : zigbee2MqttDevice.vendor.ToLower();
deviceDetailDTO.MeansOfCommunications = new List<MeansOfCommunication>
{
MeansOfCommunication.Zigbee
};
deviceDetailDTO.CreatedDate = DateTime.Now;
deviceDetailDTO.UpdatedDate = DateTime.Now;
if (zigbee2MqttDevice.type != "Coordinator")
{
// EXPOSES !
List<string> supportedOperationsDTO = new List<string>();
/*foreach (var supportedOperation in zigbee2MqttDevice.definition?.exposes)
{
supportedOperationsDTO.Add(JsonConvert.SerializeObject(supportedOperation));
}
deviceDetailDTO.SupportedOperations = supportedOperationsDTO;
deviceDetailDTO.Type = GetDeviceTypeFromZigbeeModel(zigbee2MqttDevice.definition.model);*/
}
else {
deviceDetailDTO.Type = DeviceType.Gateway;
}
if (true) //zigbee2MqttDevice.supported // TODO QUID
{
// Supported device !
createdZigbeeDevices.Add(CreateOrUpdate(_DeviceDatabaseService, _ProviderDatabaseService, _RoomDatabaseService, homeId, deviceDetailDTO, true));
}
else
{
// Not yet supported !
notSupportedZigbeeDevices.Add(deviceDetailDTO);
}
}
return new Dictionary<string, List<DeviceDetailDTO>>() {
{ "createdDevices", createdZigbeeDevices },
{ "notSupportedDevices", notSupportedZigbeeDevices }
};
}
public static async Task<Dictionary<string, List<DeviceDetailDTO>>> UpdateFromZigbeeAsync(DeviceDatabaseService _DeviceDatabaseService, ProviderDatabaseService _ProviderDatabaseService, RoomDatabaseService _RoomDatabaseService, string homeId, List<Zigbee2MqttDevice> zigbee2MqttDevices, Provider provider)
{
List<DeviceDetailDTO> updatedZigbeeDevices = new List<DeviceDetailDTO>();
List<DeviceDetailDTO> notSupportedZigbeeDevices = new List<DeviceDetailDTO>();
List<Device> existingDevices = _DeviceDatabaseService.GetByProviderId(provider.Id);
// Not necessarry
if (zigbee2MqttDevices.Count <= 0)
{
//zigbee2MqttDevices = await MqttClientService.AskDevicesAsync();
}
//zigbee2MqttDevices = zigbee2MqttDevices.Where(yd => !existingDevices.Select(ed => ed.ServiceIdentification).ToList().Contains(yd.ieee_address)).ToList();
foreach (var zigbee2MqttDevice in zigbee2MqttDevices)
{
var existingDevice = _DeviceDatabaseService.GetByServiceIdentification(zigbee2MqttDevice.ieee_address);
DeviceDetailDTO deviceDetailDTO = new DeviceDetailDTO();
deviceDetailDTO.Name = zigbee2MqttDevice.friendly_name;
deviceDetailDTO.ServiceIdentification = zigbee2MqttDevice.ieee_address;
deviceDetailDTO.ProviderId = provider.Id;
deviceDetailDTO.ProviderName = provider.Name;
deviceDetailDTO.Description = zigbee2MqttDevice.type == "Coordinator" ? "Coordinator" : zigbee2MqttDevice.definition?.description;
deviceDetailDTO.Model = zigbee2MqttDevice.type == "Coordinator" ? "Coordinator" : zigbee2MqttDevice.definition?.model; // Is the base to understand incoming messages !
deviceDetailDTO.FirmwareVersion = zigbee2MqttDevice.software_build_id;
deviceDetailDTO.Battery = zigbee2MqttDevice.power_source == null ? false : zigbee2MqttDevice.power_source.Contains("Battery");
deviceDetailDTO.ManufacturerName = zigbee2MqttDevice.definition?.vendor == null ? provider.Type.ToString() : zigbee2MqttDevice.definition?.vendor.ToLower();
deviceDetailDTO.MeansOfCommunications = new List<MeansOfCommunication>
{
MeansOfCommunication.Zigbee
};
deviceDetailDTO.GroupIds = existingDevice != null ? existingDevice.GroupIds : null;
deviceDetailDTO.Properties = existingDevice != null ? existingDevice.Properties : null;
deviceDetailDTO.RoomId = existingDevice != null ? existingDevice.RoomId : null;
deviceDetailDTO.CreatedDate = existingDevice != null ? existingDevice.CreatedDate : DateTime.Now;
deviceDetailDTO.UpdatedDate = DateTime.Now;
if (zigbee2MqttDevice.type != "Coordinator")
{
// EXPOSES !
List<string> supportedOperationsDTO = new List<string>();
if(zigbee2MqttDevice.definition?.exposes != null)
{
foreach (var supportedOperation in zigbee2MqttDevice.definition?.exposes)
{
supportedOperationsDTO.Add(JsonConvert.SerializeObject(supportedOperation));
}
deviceDetailDTO.SupportedOperations = supportedOperationsDTO;
}
deviceDetailDTO.Type = GetDeviceTypeFromZigbeeModel(zigbee2MqttDevice.definition?.model);
}
else
{
deviceDetailDTO.Type = DeviceType.Gateway;
}
if (zigbee2MqttDevice.supported || deviceDetailDTO.Type == DeviceType.Gateway)
{
// Supported device !
updatedZigbeeDevices.Add(CreateOrUpdate(_DeviceDatabaseService, _ProviderDatabaseService, _RoomDatabaseService, homeId, deviceDetailDTO, false, true));
}
else
{
// Not yet supported !
notSupportedZigbeeDevices.Add(deviceDetailDTO);
}
}
return new Dictionary<string, List<DeviceDetailDTO>>() {
{ "updatedZigbeeDevices", updatedZigbeeDevices },
{ "notSupportedDevices", notSupportedZigbeeDevices }
};
}
private static DeviceType GetDeviceTypeFromZigbeeModel(string zigbeeModel)
{
return supportedDevices.Any(sd => sd.Model == zigbeeModel) ?
// It's supported !
supportedDevices.Where(sd => sd.Model == zigbeeModel).FirstOrDefault().DeviceType :
// Not yet supported
DeviceType.Unknown;
}
public static Dictionary<string, List<DeviceDetailDTO>> CreateArloDevices(DeviceDatabaseService _DeviceDatabaseService, ProviderDatabaseService _ProviderDatabaseService, RoomDatabaseService _RoomDatabaseService, string homeId, List<ArloDevice> arloDevices, Provider provider)
{
List<DeviceDetailDTO> createdArloDevices = new List<DeviceDetailDTO>();
List<Device> existingDevices = _DeviceDatabaseService.GetByProviderId(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.ManufacturerName = provider.Type.ToString();
deviceDetailDTO.Name = arlo.deviceName;
deviceDetailDTO.Description = arlo.deviceName; // As description not exist, put name in description
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 = JsonConvert.SerializeObject(properties);
break;
case "siren":
deviceDetailDTO.Type = DeviceType.Sound;
break;
case "basestation":
deviceDetailDTO.Type = DeviceType.Gateway;
break;
}
deviceDetailDTO.MeansOfCommunications = new List<MeansOfCommunication>
{
MeansOfCommunication.Wifi // To check
};
deviceDetailDTO.CreatedDate = DateTime.Now;
deviceDetailDTO.UpdatedDate = DateTime.Now;
createdArloDevices.Add(CreateOrUpdate(_DeviceDatabaseService, _ProviderDatabaseService, _RoomDatabaseService, homeId, deviceDetailDTO, true));
}
return new Dictionary<string, List<DeviceDetailDTO>>() { { "createdDevices", createdArloDevices } }; // TODO Check if exist not supported devices
}
public static Dictionary<string, List<DeviceDetailDTO>> CreateMerossDevices(DeviceDatabaseService _DeviceDatabaseService, ProviderDatabaseService _ProviderDatabaseService, RoomDatabaseService _RoomDatabaseService, string homeId, List<MerossDevice> merossDevices, Provider provider)
{
List<DeviceDetailDTO> createdMerossDevices = new List<DeviceDetailDTO>();
List<Device> existingDevices = _DeviceDatabaseService.GetByProviderId(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.ManufacturerName = provider.Type.ToString();
deviceDetailDTO.HardwareVersion = meross.hdwareVersion;
deviceDetailDTO.Name = meross.devName;
deviceDetailDTO.Description = meross.devName; // As description not exist, put name in description
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.Multiplug;
break;
case "mss310":
deviceDetailDTO.Type = DeviceType.Plug;
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>
{
MeansOfCommunication.Wifi // TO CHECK
};
deviceDetailDTO.CreatedDate = DateTime.Now;
deviceDetailDTO.UpdatedDate = DateTime.Now;
createdMerossDevices.Add(CreateOrUpdate(_DeviceDatabaseService, _ProviderDatabaseService, _RoomDatabaseService, homeId, deviceDetailDTO, true));
}
return new Dictionary<string, List<DeviceDetailDTO>>() { { "createdDevices", createdMerossDevices } }; // TODO Check if exist not supported devices
}
public static Dictionary<string, List<DeviceDetailDTO>> CreateYeelightDevices(DeviceDatabaseService _DeviceDatabaseService, ProviderDatabaseService _ProviderDatabaseService, RoomDatabaseService _RoomDatabaseService, string homeId, List<YeelightAPI.Device> yeelightDevices, Provider provider)
{
List<DeviceDetailDTO> createdYeelightDevices = new List<DeviceDetailDTO>();
List<Device> existingDevices = _DeviceDatabaseService.GetByProviderId(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.ManufacturerName = provider.Type.ToString();
deviceDetailDTO.Name = light.Name;
deviceDetailDTO.Description = light.Name; // As description not exist, put name in description
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 = JsonConvert.SerializeObject(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>
{
MeansOfCommunication.Wifi
};
deviceDetailDTO.CreatedDate = DateTime.Now;
deviceDetailDTO.UpdatedDate = DateTime.Now;
createdYeelightDevices.Add(CreateOrUpdate(_DeviceDatabaseService, _ProviderDatabaseService, _RoomDatabaseService, homeId, deviceDetailDTO, true));
}
return new Dictionary<string, List<DeviceDetailDTO>>() { { "createdDevices", createdYeelightDevices } }; // TODO Check if exist not supported devices
}
public static Dictionary<string, List<DeviceDetailDTO>> CreateOrUpdateNetatmoDevices(DeviceDatabaseService _DeviceDatabaseService, ProviderDatabaseService _ProviderDatabaseService, RoomDatabaseService _RoomDatabaseService, string homeId, List<NetatmoHome> netatmoHomes, List<NetatmoCoachDevice> netatmoCoachDevices, Provider provider)
{
List<DeviceDetailDTO> createdNetatmoDevices = new List<DeviceDetailDTO>();
List<Device> existingDevices = _DeviceDatabaseService.GetByProviderId(provider.Id);
List<NetatmoDevice> netatmoDevices = new List<NetatmoDevice>();
foreach (var netatmoHome in netatmoHomes)
{
netatmoDevices.AddRange(netatmoHome.modules);
}
//netatmoDevices = netatmoDevices.Where(yd => !existingDevices.Select(ed => ed.ServiceIdentification).ToList().Contains(yd.id)).ToList();
foreach (var netatmoDevice in netatmoDevices)
{
bool isExist = existingDevices.Select(ed => ed.ServiceIdentification).ToList().Contains(netatmoDevice.id);
var device = existingDevices.FirstOrDefault(ed => ed.ProviderId == provider.Id && ed.ServiceIdentification == netatmoDevice.id);
DeviceDetailDTO deviceDetailDTO = isExist && device != null ? device.ToDTO() : new DeviceDetailDTO();
if (!isExist)
{
deviceDetailDTO.CreatedDate = DateTime.Now;
deviceDetailDTO.ServiceIdentification = netatmoDevice.id;
deviceDetailDTO.ProviderId = provider.Id;
deviceDetailDTO.ProviderName = provider.Name;
deviceDetailDTO.Name = netatmoDevice.name;
deviceDetailDTO.Description = netatmoDevice.name; // As description not exist, put name in description
deviceDetailDTO.Model = netatmoDevice.type;
deviceDetailDTO.IpAddress = netatmoDevice.bridge;
deviceDetailDTO.ManufacturerName = provider.Type.ToString();
deviceDetailDTO.Model = netatmoDevice.type;
}
deviceDetailDTO.ConnectionStatus = ConnectionStatus.Connected;
switch (netatmoDevice.type)
{
case "NCO": //Détecteur de Monoxyde de Carbone Intelligent
deviceDetailDTO.Type = DeviceType.Environment;
deviceDetailDTO.Battery = true;
break;
case "NACamera":
deviceDetailDTO.Type = DeviceType.Camera;
break;
case "NAPlug":
deviceDetailDTO.Type = DeviceType.Gateway;
break;
case "NATherm1":
deviceDetailDTO.Type = DeviceType.Thermostat;
deviceDetailDTO.IsTemperature = true;
break;
case "NRV":
deviceDetailDTO.Type = DeviceType.Valve;
deviceDetailDTO.IsTemperature = true;
break;
}
deviceDetailDTO.MeansOfCommunications = new List<MeansOfCommunication>
{
MeansOfCommunication.Wifi
};
deviceDetailDTO.UpdatedDate = DateTime.Now;
createdNetatmoDevices.Add(CreateOrUpdate(_DeviceDatabaseService, _ProviderDatabaseService, _RoomDatabaseService, homeId, deviceDetailDTO, !isExist));
}
//netatmoCoachDevices = netatmoCoachDevices.Where(yd => !existingDevices.Select(ed => ed.ServiceIdentification).ToList().Contains(yd._id)).ToList();
foreach (var netatmoCoachDevice in netatmoCoachDevices)
{
bool isExist = existingDevices.Select(ed => ed.ServiceIdentification).ToList().Contains(netatmoCoachDevice._id);
var device = existingDevices.FirstOrDefault(ed => ed.ProviderId == provider.Id && ed.ServiceIdentification == netatmoCoachDevice._id);
DeviceDetailDTO deviceDetailDTO = isExist && device != null ? device.ToDTO() : new DeviceDetailDTO();
if (!isExist)
{
deviceDetailDTO.CreatedDate = DateTime.Now;
deviceDetailDTO.ServiceIdentification = netatmoCoachDevice._id;
deviceDetailDTO.ProviderId = provider.Id;
deviceDetailDTO.ProviderName = provider.Name;
deviceDetailDTO.Name = netatmoCoachDevice.station_name;
deviceDetailDTO.Description = netatmoCoachDevice.module_name;
deviceDetailDTO.Model = netatmoCoachDevice.type;
deviceDetailDTO.ManufacturerName = provider.Type.ToString();
}
deviceDetailDTO.ConnectionStatus = netatmoCoachDevice.reachable ? ConnectionStatus.Connected : ConnectionStatus.Unknown;
switch (netatmoCoachDevice.type)
{
case "NHC": //Home coach classique (?)
deviceDetailDTO.Type = DeviceType.Environment;
deviceDetailDTO.Battery = false;
deviceDetailDTO.FirmwareVersion = netatmoCoachDevice.firmware.ToString();
//deviceDetailDTO.SupportedOperations = netatmoCoachDevice.data_type;
deviceDetailDTO.IsTemperature = true;
deviceDetailDTO.Temperature = netatmoCoachDevice.dashboard_data.Temperature;
deviceDetailDTO.IsHumidity = true;
deviceDetailDTO.Humidity = netatmoCoachDevice.dashboard_data.Humidity;
deviceDetailDTO.IsPressure = true;
deviceDetailDTO.Pressure = netatmoCoachDevice.dashboard_data.Pressure;
deviceDetailDTO.IsCO2 = true;
deviceDetailDTO.CO2 = netatmoCoachDevice.dashboard_data.CO2;
deviceDetailDTO.IsNoise = true;
deviceDetailDTO.Noise = netatmoCoachDevice.dashboard_data.Noise;
//TODO healthy index !
break;
}
deviceDetailDTO.MeansOfCommunications = new List<MeansOfCommunication>
{
MeansOfCommunication.Wifi
};
deviceDetailDTO.UpdatedDate = DateTime.Now;
createdNetatmoDevices.Add(CreateOrUpdate(_DeviceDatabaseService, _ProviderDatabaseService, _RoomDatabaseService, homeId, deviceDetailDTO, !isExist));
}
return new Dictionary<string, List<DeviceDetailDTO>>() { { "createdDevices", createdNetatmoDevices } };
}
public static Device UpdateDeviceFromZigbeeEvent(Device device, Zigbee2MqttRequest zigbee2MqttRequest)
{
if (zigbee2MqttRequest.state != null)
{
try
{
switch (zigbee2MqttRequest.state.ToLower()) {
case "on":
device.State = true;
break;
case "off":
default:
device.State = false;
break;
}
}
catch (Exception e)
{
Debug.Print($"State parsing issue : {zigbee2MqttRequest.state} - {e.Message}");
device.State = false;
}
}
if (zigbee2MqttRequest.brightness != null)
{
device.Brightness = zigbee2MqttRequest.brightness.Value;
}
if (zigbee2MqttRequest.linkquality != null)
{
device.LinkQuality = zigbee2MqttRequest.linkquality.Value;
}
if (zigbee2MqttRequest.battery != null)
{
device.BatteryStatus = zigbee2MqttRequest.battery.Value;
}
if (zigbee2MqttRequest.illuminance_lux != null)
{
device.Illuminance = zigbee2MqttRequest.illuminance_lux.Value;
}
if (zigbee2MqttRequest.occupancy != null)
{
device.Occupation = zigbee2MqttRequest.occupancy.Value;
}
if (zigbee2MqttRequest.temperature != null)
{
device.Temperature = zigbee2MqttRequest.temperature.Value;
}
if (zigbee2MqttRequest.humidity != null)
{
device.Humidity = zigbee2MqttRequest.humidity.Value;
}
if (zigbee2MqttRequest.alarm != null)
{
device.Alarm = zigbee2MqttRequest.alarm.Value;
}
if (zigbee2MqttRequest.voltage != null)
{
device.Voltage = zigbee2MqttRequest.voltage.Value;
}
if (zigbee2MqttRequest.contact != null)
{
device.Contact = zigbee2MqttRequest.contact.Value;
}
if (zigbee2MqttRequest.consumption != null)
{
device.Consumption = zigbee2MqttRequest.consumption.Value;
}
if (zigbee2MqttRequest.current != null)
{
device.CurrentPower = zigbee2MqttRequest.current.Value;
}
if (zigbee2MqttRequest.vibration != null)
{
device.Vibration = zigbee2MqttRequest.vibration.Value;
}
if (zigbee2MqttRequest.water_leak != null)
{
device.WaterLeak = zigbee2MqttRequest.water_leak.Value;
}
/*if (zigbee2MqttRequest.angle != null)
{
device.Angle = zigbee2MqttRequest.angle.Value;
}*/
if (zigbee2MqttRequest.action != null)
{
device.Action = zigbee2MqttRequest.action;
}
return device;
}
public static Device UpdateDeviceCapabilities(Device device, Zigbee2MqttOperations zigbee2MqttOperations)
{
if (zigbee2MqttOperations.property != null)
{
switch (zigbee2MqttOperations.property.ToLower())
{
case "power_on_behavior":
device.IsState = true;
break;
case "linkquality":
device.IsLinkQuality = true;
break;
case "air_quality":
device.IsAirQuality = true;
break;
case "temperature":
device.IsTemperature = true;
break;
case "humidity":
device.IsHumidity = true;
break;
case "battery":
device.Battery = true;
break;
case "pressure":
device.IsPressure = true;
break;
case "illuminance_lux":
device.IsIlluminance = true;
break;
case "effect":
device.IsBrightness = true;
break;
case "voltage":
device.IsVoltage = true;
break;
case "contact":
device.IsContact = true;
break;
case "smoke":
device.IsSmoke = true;
break;
case "action":
device.IsAction = true;
break;
case "vibration":
device.IsVibration = true;
break;
case "water_leak":
device.IsWaterLeak = true;
break;
case "state":
device.IsState = true;
break;
case "power":
device.IsCurrentPower = true;
break;
case "energy":
device.IsConsumption = true;
break;
case "occupancy":
device.IsOccupation = true;
break;
case "illuminance":
device.IsIlluminance = true;
break;
}
}
return device;
}
}
}