diff --git a/MyCore.Interfaces/DTO/ListResponse.cs b/MyCore.Interfaces/DTO/ListResponse.cs new file mode 100644 index 0000000..92480db --- /dev/null +++ b/MyCore.Interfaces/DTO/ListResponse.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; + +namespace MyCore.Interfaces.DTO +{ + public class ListResponse + { + public ListResponse(IEnumerable values, TParameters requestParameters) + { + this.Values = values; + this.RequestParameters = requestParameters; + } + + public IEnumerable Values { get; } + public TParameters RequestParameters { get; } + public int TotalCount { get; set; } + public int ActualCount { get; set; } + } +} \ No newline at end of file diff --git a/MyCore.Interfaces/DTO/MyControlPanel/EventDTO.cs b/MyCore.Interfaces/DTO/MyControlPanel/EventDTO.cs new file mode 100644 index 0000000..6e6c290 --- /dev/null +++ b/MyCore.Interfaces/DTO/MyControlPanel/EventDTO.cs @@ -0,0 +1,47 @@ +using MyCore.Interfaces.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace MyCore.Interfaces.DTO +{ + + public class EventDTO + { + public string Id{ get; set; } + public string HomeId{ get; set; } + public DateTime Date { get; set; } + public EventType Type { get; set; } + public string RoomId { get; set; } + } + + public class EventDetailDTO : EventDTO + { + public DeviceState DeviceState { get; set; } + public AutomationTriggered AutomationTriggered { get; set; } + public AlarmTriggered AlarmTriggered { get; set; } + } + + public class EventFilter + { + public int StartIndex { get; set; } = 0; + public int Count { get; set; } = 20; + public DateTime? DateStart { get; set; } + public DateTime? DateEnd { get; set; } + public EventType? EventType { get; set; } + public DeviceType? DeviceType { get; set; } + } + + public class EventHomeFilter : EventFilter + { + public string DeviceId { get; set; } + public string RoomId { get; set; } + } + + public class EventRoomFilter : EventFilter + { + public string DeviceId { get; set; } + } + +} diff --git a/MyCore.Interfaces/Models/MyControlPanel/Database/AlarmMode.cs b/MyCore.Interfaces/Models/MyControlPanel/Database/AlarmMode.cs index 2d4f41c..e3017cf 100644 --- a/MyCore.Interfaces/Models/MyControlPanel/Database/AlarmMode.cs +++ b/MyCore.Interfaces/Models/MyControlPanel/Database/AlarmMode.cs @@ -123,7 +123,7 @@ namespace MyCore.Interfaces.Models public string Start { get; set; } public string End { get; set; } public AlarmMode AlarmMode { get; set; } -} + } public class GeolocalizedMode { diff --git a/MyCore.Interfaces/Models/MyControlPanel/Database/Automation.cs b/MyCore.Interfaces/Models/MyControlPanel/Database/Automation.cs index 4ed2a38..89a93d9 100644 --- a/MyCore.Interfaces/Models/MyControlPanel/Database/Automation.cs +++ b/MyCore.Interfaces/Models/MyControlPanel/Database/Automation.cs @@ -54,10 +54,7 @@ namespace MyCore.Interfaces.Models Active = Active, HomeId = HomeId, CreatedDate = CreatedDate, - UpdatedDate = UpdatedDate, - //Triggers = Triggers - //Conditions = Conditions - //Actions = Actions + UpdatedDate = UpdatedDate }; } @@ -83,8 +80,8 @@ namespace MyCore.Interfaces.Models { public string ProviderId { get; set; } public string DeviceId { get; set; } - public string StateName { get; set; } - public string StateValue { get; set; } + public string StateName { get; set; } // TODO Change to AutomationState + public string StateValue { get; set; } // TODO Change to AutomationState public TriggerType type { get; set; } } diff --git a/MyCore.Interfaces/Models/MyControlPanel/Database/Event.cs b/MyCore.Interfaces/Models/MyControlPanel/Database/Event.cs new file mode 100644 index 0000000..464acb0 --- /dev/null +++ b/MyCore.Interfaces/Models/MyControlPanel/Database/Event.cs @@ -0,0 +1,99 @@ +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; +using MyCore.Interfaces.DTO; +using MyCore.Interfaces.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using static MyCore.Interfaces.Models.AlarmMode; + +namespace MyCore.Interfaces.Models +{ + /// + /// Group of events + /// + public class Event + { + [BsonId] + [BsonRepresentation(BsonType.ObjectId)] + public string Id { get; set; } + + [BsonElement("HomeId")] + [BsonRequired] + public string HomeId { get; set; } + + [BsonElement("Date")] + [BsonRequired] + public DateTime Date { get; set; } + + [BsonElement("Type")] + [BsonRequired] + public EventType Type { get; set; } + + [BsonElement("RoomId")] + public string RoomId { get; set; } + + [BsonElement("DeviceState")] + [BsonRequired] + public DeviceState DeviceState { get; set; } + + [BsonElement("AutomationTriggered")] + public AutomationTriggered AutomationTriggered { get; set; } + + [BsonElement("AlarmTriggered")] + public AlarmTriggered AlarmTriggered { get; set; } + + public EventDTO ToDTO() + { + return new EventDTO() + { + Id = Id, + HomeId = HomeId, + Date = Date, + Type = Type + }; + } + + public EventDetailDTO ToDetailDTO() + { + return new EventDetailDTO() + { + Id = Id, + HomeId = HomeId, + Date = Date, + Type = Type, + DeviceState = DeviceState, + AutomationTriggered = AutomationTriggered, + AlarmTriggered = AlarmTriggered + }; + } + } + + public enum EventType + { + DeviceState, + AutomationTriggered, + AlarmTriggered + } + + public class DeviceState + { + public string DeviceId { get; set; } + public string DeviceName { get; set; } + public string Message { get; set; } + public DeviceType DeviceType { get; set; } + } + + public class AutomationTriggered + { + public string AutomationId { get; set; } + public string AutomationName { get; set; } + } + + public class AlarmTriggered + { + public string AlarmModeId { get; set; } + public string AlarmModeName { get; set; } + public AlarmType Type { get; set; } + } +} diff --git a/MyCore/Controllers/EventController.cs b/MyCore/Controllers/EventController.cs new file mode 100644 index 0000000..b64a22f --- /dev/null +++ b/MyCore/Controllers/EventController.cs @@ -0,0 +1,265 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Security.Authentication; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using MongoDB.Bson; +using Mqtt.Client.AspNetCore.Services; +using MyCore.Interfaces.DTO; +using MyCore.Interfaces.Models; +using MyCore.Services; +using MyCore.Services.Devices; +using MyCore.Services.MyControlPanel; + +namespace MyCore.Service.Controllers +{ + [Authorize] // TODO Add ROLES (Roles = "Admin") + [Route("api/event")] + [ApiController] + public class EventController : ControllerBase + { + private HomeDatabaseService _HomeDatabaseService; + private RoomDatabaseService _RoomDatabaseService; + private EventDatabaseService _EventDatabaseService; + private DeviceDatabaseService _DeviceDatabaseService; + private readonly IMqttClientService _mqttClientService; + //private readonly IMqttOnlineClientService _mqttOnlineClientService; + + public EventController(HomeDatabaseService homeDatabaseService, RoomDatabaseService roomDatabaseService, EventDatabaseService eventDatabaseService, DeviceDatabaseService deviceDatabaseService, MqttClientServiceProvider provider)//, MqttClientOnlineServiceProvider onlineProvider) + { + this._HomeDatabaseService = homeDatabaseService; + this._RoomDatabaseService = roomDatabaseService; + this._EventDatabaseService = eventDatabaseService; + this._DeviceDatabaseService = deviceDatabaseService; + this._mqttClientService = provider.MqttClientService; + //this._mqttOnlineClientService = onlineProvider.MqttOnlineClientService; + } + + /// + /// Get events for the specified home + /// + /// Home Id + /// Filter params + [ProducesResponseType(typeof(List), 200)] + [ProducesResponseType(typeof(string), 500)] + [HttpGet("{homeId}")] + public ObjectResult Get(string homeId, [FromQuery] EventHomeFilter eventHomeFilter) // TODO Add filter by date etc + { + try + { + List events = _EventDatabaseService.GetAll(homeId); // To check if best + if (eventHomeFilter.EventType != null) + { + events = events.Where(e => e.Type == eventHomeFilter.EventType).OrderBy(e => e.Date).ToList(); + } + + if (eventHomeFilter.DeviceType != null) + { + events = events.Where(e => e.DeviceState.DeviceType == eventHomeFilter.DeviceType).OrderBy(e => e.Date).ToList(); + } + + if (eventHomeFilter.DeviceId != null) + { + events = events.Where(e => e.DeviceState.DeviceId == eventHomeFilter.DeviceId).OrderBy(e => e.Date).ToList(); + } + + if (eventHomeFilter.RoomId != null) + { + events = events.Where(e => e.RoomId == eventHomeFilter.RoomId).OrderBy(e => e.Date).ToList(); + } + + if (eventHomeFilter.DateStart != null && eventHomeFilter.DateEnd != null) { + events = events.Where(e => e.Date >= eventHomeFilter.DateStart && e.Date < eventHomeFilter.DateEnd).OrderBy(e => e.Date).ToList(); + } + + var totalCount = events.Count(); + events = events.Skip(eventHomeFilter.StartIndex).Take(eventHomeFilter.Count).ToList(); + + List eventDTOs = events.Select(d => d.ToDetailDTO()).OrderBy(e => e.Date).ToList(); + + var lr = new ListResponse(eventDTOs, eventHomeFilter); + lr.TotalCount = totalCount; + lr.ActualCount = eventDTOs.Count(); + + return new OkObjectResult(lr); + } + catch (Exception ex) + { + return new ObjectResult(ex.Message) { StatusCode = 500 }; + } + } + + /// + /// Get detail info of a specified event + /// + /// event id + [ProducesResponseType(typeof(EventDetailDTO), 200)] + [ProducesResponseType(typeof(string), 400)] + [ProducesResponseType(typeof(string), 404)] + [ProducesResponseType(typeof(string), 500)] + [HttpGet("detail/{eventId}")] + public ObjectResult GetDetail(string eventId) + { + try + { + if (eventId == null) + throw new ArgumentNullException("Incorrect parameters"); + + Event evt = _EventDatabaseService.GetById(eventId); + if (evt == null) + throw new KeyNotFoundException("Event does not exist"); + + return new OkObjectResult(evt.ToDetailDTO()); + + } + catch (ArgumentNullException ex) + { + return new BadRequestObjectResult(ex.Message) { }; + } + catch (KeyNotFoundException ex) + { + return new NotFoundObjectResult(ex.Message) { }; + } + catch (Exception ex) + { + return new ObjectResult(ex.Message) { StatusCode = 500 }; + } + } + + /// + /// Create an event + /// + /// Room to create + /*[ProducesResponseType(typeof(RoomDetailDTO), 200)] + [ProducesResponseType(typeof(string), 400)] + [ProducesResponseType(typeof(string), 500)] + [HttpPost] + public ObjectResult Create([FromBody] RoomCreateOrUpdateDetailDTO roomCreateOrUpdateDetail) + { + try + { + if (roomCreateOrUpdateDetail == null) + throw new ArgumentNullException("Incorrect parameters"); + + RoomDetailDTO roomCreated = RoomService.CreateOrUpdate(this._RoomDatabaseService, this._DeviceDatabaseService, roomCreateOrUpdateDetail.HomeId, roomCreateOrUpdateDetail, true); + + return new OkObjectResult(roomCreated); + } + catch (ArgumentNullException ex) + { + return new BadRequestObjectResult(ex.Message) { }; + } + catch (Exception ex) + { + return new ObjectResult(ex.Message) { StatusCode = 500 }; + } + }*/ + + /*/// + /// Update an event + /// + /// room to update + /*[ProducesResponseType(typeof(RoomCreateOrUpdateDetailDTO), 200)] + [ProducesResponseType(typeof(string), 404)] + [ProducesResponseType(typeof(string), 500)] + [HttpPut] + public ObjectResult Update([FromBody] RoomCreateOrUpdateDetailDTO roomCreateOrUpdateDetail) + { + try + { + if (!_RoomDatabaseService.IsExist(roomCreateOrUpdateDetail.Id)) + throw new KeyNotFoundException("Room does not exist"); + + RoomDetailDTO roomUpdated = RoomService.CreateOrUpdate(this._RoomDatabaseService, this._DeviceDatabaseService, roomCreateOrUpdateDetail.HomeId, roomCreateOrUpdateDetail, false); + + return new OkObjectResult(roomUpdated); + } + catch (KeyNotFoundException ex) + { + return new NotFoundObjectResult(ex.Message) {}; + } + catch (Exception ex) + { + return new ObjectResult(ex.Message) { StatusCode = 500 }; + } + }*/ + + /// + /// Delete an event + /// + /// Id of event to delete + [ProducesResponseType(typeof(string), 202)] + [ProducesResponseType(typeof(string), 400)] + [ProducesResponseType(typeof(string), 404)] + [ProducesResponseType(typeof(string), 500)] + [HttpDelete("{eventId}")] + public ObjectResult Delete(string eventId) + { + try + { + if (eventId == null) + throw new ArgumentNullException("Incorrect parameters"); + + if (!_EventDatabaseService.IsExist(eventId)) + throw new KeyNotFoundException("Event does not exist"); + + _EventDatabaseService.Remove(eventId); + + return new OkObjectResult("Event has been successfully deleted") { StatusCode = 202 }; + } + catch (ArgumentNullException ex) + { + return new BadRequestObjectResult(ex.Message) { }; + } + catch (KeyNotFoundException ex) + { + return new NotFoundObjectResult(ex.Message) { }; + } + catch (Exception ex) + { + return new ObjectResult(ex.Message) { StatusCode = 500 }; + } + } + + /// + /// Delete all events for a specified home + /// + /// Home Id + [ProducesResponseType(typeof(string), 202)] + [ProducesResponseType(typeof(string), 400)] + [ProducesResponseType(typeof(string), 404)] + [ProducesResponseType(typeof(string), 500)] + [HttpDelete("home/{homeId}")] + public ObjectResult DeleteAllForHome(string homeId) + { + try + { + if (homeId == null) + throw new ArgumentNullException("Incorrect parameters"); + + if (!_HomeDatabaseService.IsExist(homeId)) + throw new KeyNotFoundException("Home does not exist"); + + _EventDatabaseService.RemoveForHome(homeId); + + return new OkObjectResult("All events associated to specified home has been removed") { StatusCode = 202 }; + } + catch (ArgumentNullException ex) + { + return new BadRequestObjectResult(ex.Message) { }; + } + catch (KeyNotFoundException ex) + { + return new NotFoundObjectResult(ex.Message) { }; + } + catch (Exception ex) + { + return new ObjectResult(ex.Message) { StatusCode = 500 }; + } + } + } +} diff --git a/MyCore/Controllers/RoomController.cs b/MyCore/Controllers/RoomController.cs index c3fbca7..74404bb 100644 --- a/MyCore/Controllers/RoomController.cs +++ b/MyCore/Controllers/RoomController.cs @@ -257,7 +257,7 @@ namespace MyCore.Service.Controllers } /// - /// Delete all room for a specified home + /// Delete all rooms for a specified home /// /// Home Id [ProducesResponseType(typeof(string), 202)] @@ -277,7 +277,7 @@ namespace MyCore.Service.Controllers _RoomDatabaseService.RemoveForHome(homeId); - return new OkObjectResult("All room associated to specified home has been removed") { StatusCode = 202 }; + return new OkObjectResult("All rooms associated to specified home has been removed") { StatusCode = 202 }; } catch (ArgumentNullException ex) { diff --git a/MyCore/Extensions/MqttClientService.cs b/MyCore/Extensions/MqttClientService.cs index 60c6e2f..1c9d06c 100644 --- a/MyCore/Extensions/MqttClientService.cs +++ b/MyCore/Extensions/MqttClientService.cs @@ -36,11 +36,12 @@ namespace Mqtt.Client.AspNetCore.Services private ActionService _actionService; private HomeDatabaseService _homeDatabaseService; private AlarmDatabaseService _alarmDatabaseService; + private EventDatabaseService _eventDatabaseService; public static string lastTopic; public static long lastTimeTopic; - public MqttClientService(IMqttClientOptions options, HomeDatabaseService homeDatabaseService, DeviceDatabaseService deviceDatabaseService, GroupDatabaseService groupDatabaseService, ProviderDatabaseService providerDatabaseService, RoomDatabaseService roomDatabaseService, ActionService actionService, AutomationDatabaseService automationDatabaseService, AlarmDatabaseService alarmDatabaseService) + public MqttClientService(IMqttClientOptions options, HomeDatabaseService homeDatabaseService, DeviceDatabaseService deviceDatabaseService, GroupDatabaseService groupDatabaseService, ProviderDatabaseService providerDatabaseService, RoomDatabaseService roomDatabaseService, ActionService actionService, AutomationDatabaseService automationDatabaseService, AlarmDatabaseService alarmDatabaseService, EventDatabaseService eventDatabaseService) { this._homeDatabaseService = homeDatabaseService; this._deviceDatabaseService = deviceDatabaseService; @@ -49,6 +50,7 @@ namespace Mqtt.Client.AspNetCore.Services this._roomDatabaseService = roomDatabaseService; this._automationDatabaseService = automationDatabaseService; this._alarmDatabaseService = alarmDatabaseService; + this._eventDatabaseService = eventDatabaseService; this._actionService = actionService; Home home = this._homeDatabaseService.GetAll().ToList().Where(h => h.IsDefault).FirstOrDefault(); @@ -117,7 +119,7 @@ namespace Mqtt.Client.AspNetCore.Services { if (_actionService != null && homeId != null) { - ActionService.HandleActionFromMQTTAsync(topic, payload, _deviceDatabaseService, _groupDatabaseService, _providerDatabaseService, _roomDatabaseService, _automationDatabaseService, _alarmDatabaseService, homeId); + ActionService.HandleActionFromMQTTAsync(topic, payload, _deviceDatabaseService, _groupDatabaseService, _providerDatabaseService, _roomDatabaseService, _automationDatabaseService, _alarmDatabaseService, _eventDatabaseService, homeId); } } else diff --git a/MyCore/Extensions/ServiceCollectionExtension.cs b/MyCore/Extensions/ServiceCollectionExtension.cs index 9e76a55..8296ab8 100644 --- a/MyCore/Extensions/ServiceCollectionExtension.cs +++ b/MyCore/Extensions/ServiceCollectionExtension.cs @@ -75,6 +75,7 @@ namespace MyCore.Service.Extensions services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(serviceProvider => diff --git a/MyCore/Services/AlarmService.cs b/MyCore/Services/AlarmService.cs index 5b9ad83..2d7b283 100644 --- a/MyCore/Services/AlarmService.cs +++ b/MyCore/Services/AlarmService.cs @@ -105,23 +105,23 @@ namespace MyCore.Service.Services 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 }; + 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(), Triggers = new List(), DevicesIds = new List() }; 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 }; + 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(), DevicesIds = new List() }; 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() }; + 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(), DevicesIds = new List() }; 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() }; + 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(), DevicesIds = new List() }; 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 }; + 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(), DevicesIds = new List() }; desarmedMode = _AlarmDatabaseService.Create(desarmedMode); return HomeService.UpdateAlarmMode(_HomeDatabaseService, desarmedMode); // Activate desarmed mode by default @@ -136,7 +136,7 @@ namespace MyCore.Service.Services #endregion #region Handle message event - internal static void HandleMessage(AlarmMode alarmMode, Device deviceTrigger, string message, DeviceDatabaseService _DeviceDatabaseService, ProviderDatabaseService _ProviderDatabaseService, GroupDatabaseService _GroupDatabaseService, string homeId) + 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) @@ -174,6 +174,7 @@ namespace MyCore.Service.Services { // Correct trigger ! System.Console.WriteLine($"Correct trigger for alarm {alarmMode.Name}"); + isAction = true; #region Actions ! foreach (var action in alarmMode.Actions) @@ -321,10 +322,17 @@ namespace MyCore.Service.Services break; } - #region Send notification - check if error - // Send notification if exist - if (alarmMode.Notification && isAction) - System.Console.WriteLine($"TODO send notification"); + #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 diff --git a/MyCore/Services/AutomationService.cs b/MyCore/Services/AutomationService.cs index 2a05f32..fa8c2f4 100644 --- a/MyCore/Services/AutomationService.cs +++ b/MyCore/Services/AutomationService.cs @@ -55,7 +55,7 @@ namespace MyCore.Service.Services return _AutomationDatabaseService.Update(automation.Id, automation).ToDTO(); } - public static void HandleAutomation(List automations, Device deviceTrigger, string message, DeviceDatabaseService _DeviceDatabaseService, ProviderDatabaseService _ProviderDatabaseService, GroupDatabaseService _GroupDatabaseService, string homeId) + 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) { @@ -99,6 +99,11 @@ namespace MyCore.Service.Services 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) { diff --git a/MyCore/Services/Devices/ActionService.cs b/MyCore/Services/Devices/ActionService.cs index b188107..255d90e 100644 --- a/MyCore/Services/Devices/ActionService.cs +++ b/MyCore/Services/Devices/ActionService.cs @@ -2,6 +2,7 @@ using MyCore.Interfaces.DTO; using MyCore.Interfaces.Models; using MyCore.Interfaces.Models.Providers.Zigbee.Zigbee2Mqtt; +using MyCore.Service; using MyCore.Service.Controllers.Helpers; using MyCore.Service.Services; using MyCore.Services.MyControlPanel; @@ -21,7 +22,7 @@ namespace MyCore.Services.Devices private static Device deviceTrigger; private static string providerFromTopic; private static string deviceServiceName; - public static async Task HandleActionFromMQTTAsync(string topic, string message, DeviceDatabaseService _DeviceDatabaseService, GroupDatabaseService _GroupDatabaseService, ProviderDatabaseService _ProviderDatabaseService, RoomDatabaseService _RoomDatabaseService, AutomationDatabaseService _AutomationDatabaseService, AlarmDatabaseService _AlarmDatabaseService, string homeId) + public static async Task HandleActionFromMQTTAsync(string topic, string message, DeviceDatabaseService _DeviceDatabaseService, GroupDatabaseService _GroupDatabaseService, ProviderDatabaseService _ProviderDatabaseService, RoomDatabaseService _RoomDatabaseService, AutomationDatabaseService _AutomationDatabaseService, AlarmDatabaseService _AlarmDatabaseService, EventDatabaseService _EventDatabaseService, string homeId) { System.Console.WriteLine($"Received message {message}"); @@ -57,19 +58,23 @@ namespace MyCore.Services.Devices { #region Automations var automations = _AutomationDatabaseService.GetActiveByProvider(currentProvider.Id); - AutomationService.HandleAutomation(automations, deviceTrigger, message, _DeviceDatabaseService, _ProviderDatabaseService, _GroupDatabaseService, homeId); + AutomationService.HandleAutomation(automations, deviceTrigger, message, _DeviceDatabaseService, _ProviderDatabaseService, _GroupDatabaseService, _EventDatabaseService, homeId); #endregion #region Alarm AlarmMode alarmMode = _AlarmDatabaseService.GetCurrentActivatedAlarm(homeId); - if (alarmMode.DevicesIds.Contains(deviceTrigger.Id)) - AlarmService.HandleMessage(alarmMode, deviceTrigger, message, _DeviceDatabaseService, _ProviderDatabaseService, _GroupDatabaseService, homeId); + if (alarmMode != null) + if (alarmMode.DevicesIds.Contains(deviceTrigger.Id)) + AlarmService.HandleMessage(alarmMode, deviceTrigger, message, _DeviceDatabaseService, _ProviderDatabaseService, _GroupDatabaseService, _EventDatabaseService, homeId); #endregion // Update last state of devices deviceTrigger.LastStateDate = DateTime.Now; deviceTrigger.LastState = message; _DeviceDatabaseService.Update(deviceTrigger); + + EventDetailDTO eventDetailDTO = new EventDetailDTO() { Type = EventType.DeviceState, HomeId = homeId, RoomId = deviceTrigger.RoomId, DeviceState = new DeviceState() { DeviceId = deviceTrigger.Id, DeviceName = deviceTrigger.Name, DeviceType = deviceTrigger.Type, Message = message } }; + EventService.CreateOrUpdate(_EventDatabaseService, homeId, eventDetailDTO, true); } else { diff --git a/MyCore/Services/EventService.cs b/MyCore/Services/EventService.cs new file mode 100644 index 0000000..0a78a09 --- /dev/null +++ b/MyCore/Services/EventService.cs @@ -0,0 +1,46 @@ +using MyCore.Interfaces.DTO; +using MyCore.Interfaces.Models; +using MyCore.Services; +using MyCore.Services.MyControlPanel; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace MyCore.Service +{ + public class EventService + { + public static EventDetailDTO CreateOrUpdate(EventDatabaseService _EventDatabaseService, string homeId, EventDetailDTO eventDetailDTO, bool create) + { + Event evt; + if (create) + { + evt = new Event(); + evt.Date = DateTime.Now; + } + else + { + evt = _EventDatabaseService.GetById(eventDetailDTO.Id); + } + + evt.HomeId = homeId; + evt.Type = eventDetailDTO.Type; + evt.RoomId = eventDetailDTO.RoomId; + evt.DeviceState = eventDetailDTO.DeviceState; + evt.AutomationTriggered = eventDetailDTO.AutomationTriggered; + evt.AlarmTriggered = eventDetailDTO.AlarmTriggered; + + if (create) + { + evt = _EventDatabaseService.Create(evt); + } + else + { + evt = _EventDatabaseService.Update(evt); + } + + return evt.ToDetailDTO(); + } + } +} diff --git a/MyCore/Services/MyControlPanel/Database/EventDatabaseService.cs b/MyCore/Services/MyControlPanel/Database/EventDatabaseService.cs new file mode 100644 index 0000000..27daa03 --- /dev/null +++ b/MyCore/Services/MyControlPanel/Database/EventDatabaseService.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using MyCore.Interfaces.Models; +using Microsoft.Extensions.Configuration; +using MongoDB.Driver; + +namespace MyCore.Services +{ + public class EventDatabaseService + { + private readonly IMongoCollection _Events; + + public EventDatabaseService(IConfiguration config) + { + var client = new MongoClient(config.GetConnectionString("MyCoreDb")); + var database = client.GetDatabase("MyCoreDb"); + _Events = database.GetCollection("Events"); + } + public List GetAll(string homeId) + { + return _Events.Find(d => d.HomeId == homeId).ToList(); + } + + public List GetEventType(EventType? eventType) + { + return _Events.Find(d => d.Type == (EventType) eventType).ToList(); + } + + public Event GetById(string id) + { + return _Events.Find(d => d.Id == id).FirstOrDefault(); + } + + public List GetByDeviceId(string id) + { + return _Events.Find(d => d.Type == EventType.DeviceState && d.DeviceState.DeviceId == id).ToList(); + } + + public bool IsExist(string id) + { + return _Events.Find(d => d.Id == id).FirstOrDefault() != null ? true : false; + } + + public Event Create(Event eventIn) + { + _Events.InsertOne(eventIn); + return eventIn; + } + + public Event Update(Event eventIn) + { + _Events.ReplaceOne(evt => evt.Id == eventIn.Id, eventIn); + return eventIn; + } + + public void Remove(string id) + { + _Events.DeleteOne(evt => evt.Id == id); + } + + public void RemoveForHome(string homeId) + { + _Events.DeleteMany(evt => evt.HomeId == homeId); + } + } +} diff --git a/MyCore/Startup.cs b/MyCore/Startup.cs index 01b49d4..fd54926 100644 --- a/MyCore/Startup.cs +++ b/MyCore/Startup.cs @@ -162,6 +162,7 @@ namespace MyCore services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); services.AddMqttClientHostedService(); // Todo client files (a lot are useless) } diff --git a/MyCore/appsettings.json b/MyCore/appsettings.json index 835aad2..a10dbb8 100644 --- a/MyCore/appsettings.json +++ b/MyCore/appsettings.json @@ -1,8 +1,8 @@ { "ConnectionStrings": { "BookstoreDb": "mongodb://admin:MioTech4ever!@localhost:27017", - //"MyCoreDb": "mongodb://admin:MioTech4ever!@192.168.31.140:27017", // DEV - "MyCoreDb": "mongodb://admin:MioTech4ever!@localhost:27017" + "MyCoreDb": "mongodb://admin:MioTech4ever!@192.168.31.140:27017" // DEV + //"MyCoreDb": "mongodb://admin:MioTech4ever!@localhost:27017" }, "Logging": { "LogLevel": {