using Mqtt.Client.AspNetCore.Services; using MyCore.Interfaces.DTO; using MyCore.Interfaces.Models; using MyCore.Service.Controllers.Helpers; using MyCore.Services; using MyCore.Services.MyControlPanel; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using static Mqtt.Client.AspNetCore.Services.MqttClientMerossService; namespace MyCore.Service.Services { public class AutomationService { public static AutomationDTO CreateOrUpdate(AutomationDatabaseService _AutomationDatabaseService, string homeId, AutomationDetailDTO automationDetailDTO, bool create) { Automation automation; if (create) automation = new Automation(); else { automation = _AutomationDatabaseService.GetById(automationDetailDTO.Id); } automation.HomeId = homeId; automation.Name = automationDetailDTO.Name; automation.Active = automationDetailDTO.Active; automation.CreatedDate = create ? DateTime.Now : automation.CreatedDate; automation.UpdatedDate = DateTime.Now; automation.Triggers = automationDetailDTO.Triggers; automation.Conditions = automationDetailDTO.Conditions; automation.Actions = automationDetailDTO.Actions; var allDeviceIds = new List(); allDeviceIds.AddRange(automation.Triggers.Select(t => t.DeviceId)); // Only take the deviceIds from triggers /*allDeviceIds.AddRange(automation.Conditions.Select(t => t.DeviceId)); foreach(var action in automation.Actions) { if (action.DeviceId != null) { allDeviceIds.Add(action.DeviceId); } if (action.GroupId != null) { } }*/ automation.DevicesIds = allDeviceIds; if (create) return _AutomationDatabaseService.Create(automation).ToDTO(); else return _AutomationDatabaseService.Update(automation.Id, automation).ToDTO(); } public static void HandleAutomation(List automations, Device deviceTrigger, string message, DeviceDatabaseService _DeviceDatabaseService, ProviderDatabaseService _ProviderDatabaseService, GroupDatabaseService _GroupDatabaseService, EventDatabaseService _EventDatabaseService, string homeId) { foreach (var automation in automations) { try { // todo check if not null and if more than one element if (deviceTrigger != null && automation.Triggers.Any(t => t.DeviceId == deviceTrigger.Id)) { var automationTriggers = automation.Triggers.Where(t => t.DeviceId == deviceTrigger.Id).ToList(); // Test for each automation trigger found foreach (var automationTrigger in automationTriggers) { List exposes = DevicesHelper.GetDeviceExposes(deviceTrigger); var triggerStateValueCheck = (object)null; // Try to get automationTrigger.StateName of zigbee device var expose = exposes.Where(e => e.name == automationTrigger.StateName).FirstOrDefault(); bool validTrigger = expose != null; // No expose found.. => the device has not the correct state => not correct automation try { // Try to get specific field from message var dic = JsonConvert.DeserializeObject>(message); triggerStateValueCheck = dic[automationTrigger.StateName]; // if action slide => get slide } catch (Exception ex) { validTrigger = false; } if (validTrigger && automationTrigger.StateValue.ToLower() == triggerStateValueCheck.ToString().ToLower()) { // Correct trigger ! System.Console.WriteLine($"Correct trigger for automation {automation.Name}"); var isConditionsRespected = CheckConditions(automation.Conditions); if (!isConditionsRespected.Any(cr => !cr)) { System.Console.WriteLine("Conditions respected !"); // Create an event EventDetailDTO eventDetailDTO = new EventDetailDTO() { Type = EventType.AutomationTriggered, HomeId = homeId, RoomId = deviceTrigger.RoomId, AutomationTriggered = new AutomationTriggered() { AutomationId = automation.Id, AutomationName = automation.Name }, DeviceState = new DeviceState() { DeviceId = deviceTrigger.Id, DeviceName = deviceTrigger.Name, DeviceType = deviceTrigger.Type, Message = message } }; EventService.CreateOrUpdate(_EventDatabaseService, homeId, eventDetailDTO, true); foreach (var action in automation.Actions) { HandleAction(homeId, action, _ProviderDatabaseService, _DeviceDatabaseService, _GroupDatabaseService) ; } } else { System.Console.WriteLine($"One or more condition aren't respected"); } } } } } catch (Exception ex) { System.Console.WriteLine($"Exeption in one of automation logic - {ex}"); } } } public static void HandleAction(string homeId, Interfaces.Models.Action action, ProviderDatabaseService providerDatabaseService, DeviceDatabaseService deviceDatabaseService, GroupDatabaseService groupDatabaseService) { var DeviceNameForAction = ""; Device actionDeviceToTest = new Device(); // Retrieve action type switch (action.Type) { case ActionType.DEVICE: var deviceAction = deviceDatabaseService.GetById(action.DeviceId); var providerActionTest = providerDatabaseService.GetById(homeId, action.ProviderId); DeviceNameForAction = deviceAction.Name; actionDeviceToTest = deviceAction; System.Console.WriteLine($"We get a device action ! Name={deviceAction.Name} Type={deviceAction.Type}"); System.Console.WriteLine($"Check action provider type ! Type={providerActionTest.Type} Name={providerActionTest.Name}"); break; case ActionType.GROUP: var groupAction = groupDatabaseService.GetById(action.GroupId); DeviceNameForAction = groupAction.Name; System.Console.WriteLine($"We get a group action ! Name={groupAction.Name} Type={groupAction.Type}"); System.Console.WriteLine($"Check action zigbeeGroupAction type ! Type={groupAction.Type}"); // Check state of first device of a group actionDeviceToTest = deviceDatabaseService.GetByGroup(groupAction.Id).FirstOrDefault(); // TODO : Send error if no device found ! break; case ActionType.MQTT: // take raw request and send it ! RawRequestMQTT rawRequestMQTT = JsonConvert.DeserializeObject(action.RawRequest); if (rawRequestMQTT != null) { // SEND REQUEST System.Console.WriteLine($"Send raw request mqtt! topic:{rawRequestMQTT.topic} - message: {rawRequestMQTT.message}"); MqttClientService.PublishMessage(rawRequestMQTT.topic, rawRequestMQTT.message); } break; case ActionType.HTTP: // Correct way ? // TODO break; } var providerAction = providerDatabaseService.GetById(homeId, action.ProviderId); // Check if device exist if (actionDeviceToTest != null && providerAction != null) { switch (providerAction.Type) { case ProviderType.zigbee2mqtt: try { DevicesHelper.ActionOnZigbee2Mqtt(actionDeviceToTest, action, DeviceNameForAction); } catch (Exception ex) { System.Console.WriteLine($"ActionOnZigbee2Mqtt result in error: {ex}"); } break; case ProviderType.meross: try { DevicesHelper.ActionOnMeross(deviceDatabaseService, actionDeviceToTest, action, DeviceNameForAction); } catch (Exception ex) { System.Console.WriteLine($"ActionOnMeross result in error: {ex}"); } break; case ProviderType.yeelight: try { DevicesHelper.ActionOnYeelight(deviceDatabaseService, actionDeviceToTest, action); } catch (Exception ex) { System.Console.WriteLine($"ActionOnYeelight result in error: {ex}"); } break; } } else { System.Console.WriteLine($"Device or group found in action incorrect"); } } public static List CheckConditions(List conditions) { var isConditionsRespected = conditions.Count <= 0 ? new List() { true } : new List(new bool[conditions.Count]); var i = 0; foreach (var condition in conditions) { switch (condition.Type) { case ConditionType.STATE: break; case ConditionType.TIME: TimeSpan now = DateTime.Now.TimeOfDay; var test = JsonConvert.SerializeObject(now); TimeSpan start = JsonConvert.DeserializeObject(condition.StartTime); TimeSpan end = JsonConvert.DeserializeObject(condition.EndTime); // => Test if ok with night ! if (start <= end) { // start and stop times are in the same day if (now >= start && now <= end) { isConditionsRespected[i] = true; } } else { // start and stop times are in different days if (now >= start || now <= end) { isConditionsRespected[i] = true; } } break; } i++; } return isConditionsRespected; } } }