mycorerepository/MyCore/Services/AlarmService.cs

345 lines
18 KiB
C#

using Mqtt.Client.AspNetCore.Services;
using MyCore.Interfaces.DTO;
using MyCore.Interfaces.Models;
using MyCore.Service.Controllers.Helpers;
using MyCore.Services;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using static MyCore.Interfaces.Models.AlarmMode;
namespace MyCore.Service.Services
{
public class AlarmService
{
#region DB - classic methods
public static AlarmModeDetailDTO CreateOrUpdate(AlarmDatabaseService _AlarmDatabaseService, DeviceDatabaseService _DeviceDatabaseService, string homeId, AlarmModeCreateOrUpdateDetailDTO alarmModeCreateOrUpdateDetailDTO, bool create)
{
AlarmMode alarmMode;
if (create)
{
alarmMode = new AlarmMode();
alarmMode.CreatedDate = DateTime.Now;
}
else
alarmMode = _AlarmDatabaseService.GetById(alarmModeCreateOrUpdateDetailDTO.Id);
alarmMode.HomeId = homeId;
alarmMode.Name = alarmModeCreateOrUpdateDetailDTO.Name;
alarmMode.UpdatedDate = DateTime.Now;
alarmMode.Type = alarmModeCreateOrUpdateDetailDTO.Type;
alarmMode.Notification = alarmModeCreateOrUpdateDetailDTO.Notification;
switch (alarmMode.Type)
{
case AlarmType.Home:
case AlarmType.Absent:
case AlarmType.Custom:
alarmMode.Triggers = alarmModeCreateOrUpdateDetailDTO.Triggers;
alarmMode.Actions = alarmModeCreateOrUpdateDetailDTO.Actions;
break;
case AlarmType.Geolocalized:
// 1. Select GPS coord and zone
// 2. Which mode when absent
// 3. Which mode when present
alarmMode.GeolocalizedMode = alarmModeCreateOrUpdateDetailDTO.GeolocalizedMode;
break;
case AlarmType.Programmed:
// Define periods when specific mode are activated (existing ones)
alarmMode.ProgrammedMode = alarmModeCreateOrUpdateDetailDTO.ProgrammedMode;
break;
case AlarmType.Desarmed:
break;
}
List<string> devicesIdsTriggers = alarmModeCreateOrUpdateDetailDTO.Triggers.Select(t => t.DeviceId).ToList();
alarmMode.DevicesIds = devicesIdsTriggers;
List<string> devicesIdsActions = alarmModeCreateOrUpdateDetailDTO.Actions.Select(t => t.DeviceId).ToList();
alarmMode.DevicesIds.AddRange(devicesIdsActions);
if (create)
alarmMode = _AlarmDatabaseService.Create(alarmMode);
else
alarmMode = _AlarmDatabaseService.Update(alarmMode);
// List devices for DTO (only)
List<Device> devices = new List<Device>();
foreach (var deviceId in alarmMode.DevicesIds)
{
Device device = _DeviceDatabaseService.GetById(deviceId);
if (device != null)
{
devices.Add(device);
}
}
return alarmMode.ToDetailDTO(devices.Select(d => d.ToDTO()).ToList());
}
public static bool Activate(AlarmDatabaseService _AlarmDatabaseService, AlarmMode alarmModeToActivate, HomeDatabaseService _HomeDatabaseService)
{
try {
// Desactivate current mode
AlarmMode alarmMode = _AlarmDatabaseService.GetCurrentActivatedAlarm(alarmModeToActivate.HomeId);
alarmMode.Activated = false;
alarmMode = _AlarmDatabaseService.Update(alarmMode);
// Activate the new one
alarmModeToActivate.Activated = true;
alarmModeToActivate = _AlarmDatabaseService.Update(alarmModeToActivate);
// Update home
return HomeService.UpdateAlarmMode(_HomeDatabaseService, alarmModeToActivate); // Change active mode for home
}
catch (Exception ex)
{
// Todo add log
System.Console.WriteLine($"An error has occurred during activating alarm {alarmModeToActivate.Name} : {ex.Message}");
return false;
}
}
public static bool CreateDefaultAlarmModes(HomeDatabaseService _HomeDatabaseService, AlarmDatabaseService _AlarmDatabaseService, Home home)
{
try
{
// Home mode
AlarmMode homeMode = new AlarmMode() { HomeId = home.Id, Name = AlarmType.Home.ToString(), Type = AlarmType.Home, Activated = false, IsDefault = true, Notification = true, CreatedDate = DateTime.Now, UpdatedDate = DateTime.Now, Actions = new List<Interfaces.Models.Action>(), Triggers = new List<Trigger>(), DevicesIds = new List<string>() };
homeMode = _AlarmDatabaseService.Create(homeMode);
// Absent mode
AlarmMode absentMode = new AlarmMode() { HomeId = home.Id, Name = AlarmType.Absent.ToString(), Type = AlarmType.Absent, Activated = false, IsDefault = true, Notification = true, CreatedDate = DateTime.Now, UpdatedDate = DateTime.Now, Triggers = new List<Trigger>(), DevicesIds = new List<string>() };
absentMode = _AlarmDatabaseService.Create(absentMode);
// Geolocalized
AlarmMode geolocalizedMode = new AlarmMode() { HomeId = home.Id, Name = AlarmType.Geolocalized.ToString(), Type = AlarmType.Geolocalized, Activated = false, IsDefault = true, Notification = true, CreatedDate = DateTime.Now, UpdatedDate = DateTime.Now, GeolocalizedMode = new GeolocalizedMode(), Triggers = new List<Trigger>(), DevicesIds = new List<string>() };
geolocalizedMode = _AlarmDatabaseService.Create(geolocalizedMode);
// Programmed mode
AlarmMode programmedMode = new AlarmMode() { HomeId = home.Id, Name = AlarmType.Programmed.ToString(), Type = AlarmType.Programmed, Activated = false, IsDefault = true, Notification = true, CreatedDate = DateTime.Now, UpdatedDate = DateTime.Now, ProgrammedMode = new ProgrammedMode(), Triggers = new List<Trigger>(), DevicesIds = new List<string>() };
programmedMode = _AlarmDatabaseService.Create(programmedMode);
// Desarmed mode
AlarmMode desarmedMode = new AlarmMode() { HomeId = home.Id, Name = AlarmType.Desarmed.ToString(), Type = AlarmType.Desarmed, Activated = true, IsDefault = true, Notification = true, CreatedDate = DateTime.Now, UpdatedDate = DateTime.Now, Triggers = new List<Trigger>(), DevicesIds = new List<string>() };
desarmedMode = _AlarmDatabaseService.Create(desarmedMode);
return HomeService.UpdateAlarmMode(_HomeDatabaseService, desarmedMode); // Activate desarmed mode by default
}
catch (Exception ex)
{
// Todo add log
System.Console.WriteLine($"An error has occurred during creating default alarm modes for home {home.Name} : {ex.Message}");
return false;
}
}
#endregion
#region Handle message event
internal static void HandleMessage(AlarmMode alarmMode, Device deviceTrigger, string message, DeviceDatabaseService _DeviceDatabaseService, ProviderDatabaseService _ProviderDatabaseService, GroupDatabaseService _GroupDatabaseService, EventDatabaseService _EventDatabaseService, string homeId)
{
bool isAction = false;
switch (alarmMode.Type)
{
case AlarmType.Home:
case AlarmType.Absent:
case AlarmType.Custom:
// Check if trigger status correct
var alarmTriggers = alarmMode.Triggers.Where(t => t.DeviceId == deviceTrigger.Id).ToList();
#region Check trigger
foreach (var alarmTrigger in alarmTriggers)
{
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 == alarmTrigger.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[alarmTrigger.StateName]; // if action slide => get slide
}
catch (Exception ex)
{
validTrigger = false;
}
if (validTrigger && alarmTrigger.StateValue.ToLower() == triggerStateValueCheck.ToString().ToLower())
{
// Correct trigger !
System.Console.WriteLine($"Correct trigger for alarm {alarmMode.Name}");
isAction = true;
#region Actions !
foreach (var action in alarmMode.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");
}
}
#endregion
}
}
#endregion
break;
case AlarmType.Geolocalized:
// Todo check geolocalisation..
break;
case AlarmType.Programmed:
try {
List<TimePeriodAlarm> CurrentDayLogic = new List<TimePeriodAlarm>();
switch (DateTime.Now.DayOfWeek)
{
case DayOfWeek.Monday:
CurrentDayLogic = alarmMode.ProgrammedMode.Monday;
break;
case DayOfWeek.Tuesday:
CurrentDayLogic = alarmMode.ProgrammedMode.Tuesday;
break;
case DayOfWeek.Wednesday:
CurrentDayLogic = alarmMode.ProgrammedMode.Wednesday;
break;
case DayOfWeek.Thursday:
CurrentDayLogic = alarmMode.ProgrammedMode.Thursday;
break;
case DayOfWeek.Friday:
CurrentDayLogic = alarmMode.ProgrammedMode.Friday;
break;
case DayOfWeek.Saturday:
CurrentDayLogic = alarmMode.ProgrammedMode.Saturday;
break;
case DayOfWeek.Sunday:
CurrentDayLogic = alarmMode.ProgrammedMode.Sunday;
break;
default:
throw new Exception("Error in days");
}
// Todo retrieve current time period depending the current time.
//=> TODO
isAction = false;
}
catch (Exception ex) {
// Todo log
System.Console.WriteLine($"Error in alarm programmed mode {ex.Message}");
}
break;
case AlarmType.Desarmed:
isAction = false;
// Do nothing, alarm is disarmed :)
break;
}
#region Send notification - check if error - save event
if (isAction)
{
// Create an event
EventDetailDTO eventDetailDTO = new EventDetailDTO() { Type = EventType.AlarmTriggered, HomeId = homeId, RoomId = deviceTrigger.RoomId, AlarmTriggered = new AlarmTriggered() { AlarmModeId = alarmMode.Id, AlarmModeName = alarmMode.Name }, DeviceState = new DeviceState() { DeviceId = deviceTrigger.Id, DeviceName = deviceTrigger.Name, DeviceType = deviceTrigger.Type, Message = message } };
EventService.CreateOrUpdate(_EventDatabaseService, homeId, eventDetailDTO, true);
// Send notification if exist
if (alarmMode.Notification)
System.Console.WriteLine($"TODO send notification");
}
#endregion
}
#endregion
}
}