mycorerepository/MyCore/Services/AutomationService.cs

254 lines
14 KiB
C#

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<string>();
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<Automation> 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<Expose> 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<Dictionary<string, string>>(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)
{
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<RawRequestMQTT>(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");
}
}
}
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 List<bool> CheckConditions(List<Condition> conditions)
{
var isConditionsRespected = conditions.Count <= 0 ? new List<bool>() { true } : new List<bool>(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<TimeSpan>(condition.StartTime);
TimeSpan end = JsonConvert.DeserializeObject<TimeSpan>(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;
}
}
}