MC Add group controller + add groupFromZigbee + in action service

This commit is contained in:
Thomas Fransolet 2021-03-15 19:41:39 +01:00
parent ed47b2659d
commit ee568d17da
15 changed files with 768 additions and 70 deletions

View File

@ -5,10 +5,29 @@ using System.Threading.Tasks;
namespace MyCore.Interfaces.DTO
{
public class GroupDTO
public class GroupSummaryDTO
{
public string Id { get; set; }
public string UserId { get; set; }
public string Name { get; set; }
public List<string> Devices { get; set; }
public string Type { get; set; }
public bool IsAlarm { get; set; }
}
public class GroupDetailDTO : GroupSummaryDTO
{
public DateTime CreatedDate { get; set; }
public DateTime UpdatedDate { get; set; }
public List<DeviceDetailDTO> Devices { get; set; }
}
public class GroupCreateOrUpdateDetailDTO : GroupSummaryDTO
{
public List<string> DeviceIds { get; set; }
}
}

View File

@ -103,16 +103,22 @@ namespace MyCore.Interfaces.Models
public class Action
{
public string GroupId { get; set; }
public string DeviceId { get; set; }
public string StateName { get; set; } // example : state
public string StateValue { get; set; } // example : ON
public string ProviderId { get; set; } // TODO
public string DeviceType { get; set; } // TODO
public string RawRequest { get; set; } // http, mqtt
public string ProviderId { get; set; }
public Type Type { get; set; }
}
public enum Type
{
DELAY,
DEVICE
}
DEVICE,
HTTP,
ZIGBEE2MQTT,
MQTT,
GROUP
}
}

View File

@ -111,8 +111,7 @@ namespace MyCore.Interfaces.Models
Status = Status,
ConnectionStatus = ConnectionStatus,
ProviderId = ProviderId,
LocationId = LocationId, // Check if correct way
// Location =
LocationId = LocationId, // Include room id
LastStateDate = LastStateDate,
Battery = Battery,
BatteryStatus = BatteryStatus
@ -132,8 +131,7 @@ namespace MyCore.Interfaces.Models
Port = Port,
FirmwareVersion = FirmwareVersion,
ConnectionStatus = ConnectionStatus,
LocationId = LocationId, // Check if correct way
// Location =
LocationId = LocationId, // Include room id
MeansOfCommunications = MeansOfCommunications,
CreatedDate = CreatedDate,
UpdatedDate = UpdatedDate,

View File

@ -14,20 +14,60 @@ namespace MyCore.Interfaces.Models
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
[BsonElement("UserId")]
[BsonRequired]
public string UserId { get; set; }
[BsonElement("Name")]
[BsonRequired]
public string Name { get; set; }
[BsonElement("Devices")]
public List<string> Devices { get; set; }
[BsonElement("Type")]
[BsonRequired]
public string Type { get; set; } // zigbee2mqtt specific => generated from zigbee groups config
// TODO specific group = Alarm, sound etc ? Useless if we check device type during creation ?
public GroupDTO ToDTO()
[BsonElement("ServiceIdentification")] // For zigbee2mqtt
[BsonRequired]
public int ServiceIdentification { get; set; }
[BsonElement("IsAlarm")]
[BsonRequired]
public bool IsAlarm { get; set; } // For specific group = Alarm
[BsonElement("CreatedDate")]
public DateTime CreatedDate { get; set; }
[BsonElement("UpdatedDate")]
public DateTime UpdatedDate { get; set; }
[BsonElement("DevicesIds")]
public List<string> DevicesIds { get; set; }
public GroupSummaryDTO ToSummaryDTO()
{
return new GroupDTO()
return new GroupSummaryDTO()
{
Id = Id,
UserId = UserId,
Name = Name,
Devices = Devices
Type = Type,
IsAlarm = IsAlarm
};
}
public GroupDetailDTO ToDTO(List<DeviceDetailDTO> devicesDetail)
{
return new GroupDetailDTO()
{
Id = Id,
UserId = UserId,
Name = Name,
Type = Type,
IsAlarm = IsAlarm,
CreatedDate = CreatedDate,
UpdatedDate = UpdatedDate,
Devices = devicesDetail
};
}
}

View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace MyCore.Interfaces.Models
{
public class Zigbee2MqttGroup
{
public string friendly_name { get; set; }
public int id { get; set; }
public List<Member> members { get; set; }
}
public class Member
{
public int endpoint { get; set; }
public string ieee_address { get; set; }
}
}

View File

@ -29,6 +29,7 @@ namespace MyCore.Service.Controllers
private readonly ILogger<AuthenticationController> _logger;
private readonly TokensService _tokensService;
private readonly DeviceDatabaseService _DeviceDatabaseService;
private readonly GroupDatabaseService _GroupDatabaseService;
private readonly ProviderDatabaseService _ProviderDatabaseService;
private readonly LocationDatabaseService _LocationDatabaseService;
private readonly UserDatabaseService _UserDatabaseService;
@ -37,11 +38,12 @@ namespace MyCore.Service.Controllers
private readonly IMqttClientService _mqttClientService;
//private readonly IMqttOnlineClientService _mqttOnlineClientService;
public AuthenticationController(ILogger<AuthenticationController> logger, TokensService tokensService, DeviceDatabaseService DeviceDatabaseService, ProviderDatabaseService ProviderDatabaseService, LocationDatabaseService LocationDatabaseService, UserDatabaseService UserDatabaseService, ActionService ActionService, AutomationDatabaseService AutomationDatabaseService, MqttClientServiceProvider provider)//, MqttClientOnlineServiceProvider onlineProvider)
public AuthenticationController(ILogger<AuthenticationController> logger, TokensService tokensService, DeviceDatabaseService DeviceDatabaseService, GroupDatabaseService GroupDatabaseService, ProviderDatabaseService ProviderDatabaseService, LocationDatabaseService LocationDatabaseService, UserDatabaseService UserDatabaseService, ActionService ActionService, AutomationDatabaseService AutomationDatabaseService, MqttClientServiceProvider provider)//, MqttClientOnlineServiceProvider onlineProvider)
{
_logger = logger;
_tokensService = tokensService;
_DeviceDatabaseService = DeviceDatabaseService;
_GroupDatabaseService = GroupDatabaseService;
_ProviderDatabaseService = ProviderDatabaseService;
_LocationDatabaseService = LocationDatabaseService;
_UserDatabaseService = UserDatabaseService;
@ -55,6 +57,9 @@ namespace MyCore.Service.Controllers
{
try
{
// For TEST
email = "test@email.be";
password = "kljqsdkljqsd";
var token = _tokensService.Authenticate(email.ToLower(), password);
// Set user token ?
@ -62,7 +67,7 @@ namespace MyCore.Service.Controllers
if (user != null) {
System.Console.WriteLine($"Init userId for MqqClientService ! {user.Email}");
MqttClientService.SetServices(_DeviceDatabaseService, _ProviderDatabaseService, _LocationDatabaseService, _ActionService, _AutomationDatabaseService, user.Id);
MqttClientService.SetServices(_DeviceDatabaseService, _GroupDatabaseService, _ProviderDatabaseService, _LocationDatabaseService, _ActionService, _AutomationDatabaseService, user.Id);
}
return Ok(token);

View File

@ -0,0 +1,335 @@
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.Service.Services;
using MyCore.Services;
using MyCore.Services.Devices;
using MyCore.Services.MyControlPanel;
namespace MyCore.Service.Controllers
{
[Authorize] // TODO Add ROLES (Roles = "Admin")
[Route("api/group")]
[ApiController]
public class GroupController : ControllerBase
{
private UserDatabaseService _UserDatabaseService;
private GroupDatabaseService _GroupDatabaseService;
private DeviceDatabaseService _DeviceDatabaseService;
private ProviderDatabaseService _ProviderDatabaseService;
private readonly IMqttClientService _mqttClientService;
//private readonly IMqttOnlineClientService _mqttOnlineClientService;
public GroupController(UserDatabaseService userDatabaseService, GroupDatabaseService groupDatabaseService, DeviceDatabaseService deviceDatabaseService, ProviderDatabaseService providerDatabaseService, MqttClientServiceProvider provider)//, MqttClientOnlineServiceProvider onlineProvider)
{
this._UserDatabaseService = userDatabaseService;
this._GroupDatabaseService = groupDatabaseService;
this._DeviceDatabaseService = deviceDatabaseService;
this._ProviderDatabaseService = providerDatabaseService;
this._mqttClientService = provider.MqttClientService;
//this._mqttOnlineClientService = onlineProvider.MqttOnlineClientService;
}
/// <summary>
/// Get all groups for the specified user
/// </summary>
/// <param name="userId">Id of user</param>
[ProducesResponseType(typeof(List<GroupSummaryDTO>), 200)]
[HttpGet("{userId}")]
public ObjectResult GetAll(string userId)
{
try
{
List<Group> Groups = _GroupDatabaseService.GetAll(userId);
List<GroupSummaryDTO> groupsSummaryDTO = Groups.Select(d => d.ToSummaryDTO()).ToList();
return new OkObjectResult(groupsSummaryDTO);
}
catch (Exception ex)
{
return new ObjectResult(ex.Message) { StatusCode = 500 };
}
}
/// <summary>
/// Get detail info of a specified group
/// </summary>
/// <param name="userId">user id</param>
/// <param name="groupId">groupid</param>
[ProducesResponseType(typeof(GroupDetailDTO), 200)]
[HttpGet("detail/{groupId}")]
public ObjectResult GetDetail(string userId, string groupId)
{
try
{
if (userId != null && groupId != null)
{
Group group = _GroupDatabaseService.GetById(groupId);
List<Device> devices = _DeviceDatabaseService.GetByLocation(group.UserId, groupId);
return new OkObjectResult(group.ToDTO(devices.Select(d => d.ToDTO()).ToList()));
}
else
{
return new ObjectResult("Invalid parameters") { StatusCode = 400 };
}
}
catch (Exception ex)
{
return new ObjectResult(ex.Message) { StatusCode = 500 };
}
}
/// <summary>
/// Get list of group from a type
/// </summary>
/// <param name="userId">user Id</param>
/// <param name="type">group type</param>
[ProducesResponseType(typeof(List<GroupSummaryDTO>), 200)]
[HttpGet("{userId}/type/{type}")]
public ObjectResult GetGroupsByType(string userId, string type) // Change string type to enum ? Lights etc ?
{
try
{
if (userId != null)
{
List<Group> groups = _GroupDatabaseService.GetByType(userId, type);
return new OkObjectResult(groups.Select(d => d.ToSummaryDTO()));
}
else
{
return new ObjectResult("Invalid parameters") { StatusCode = 400 };
}
}
catch (Exception ex)
{
return new ObjectResult(ex.Message) { StatusCode = 500 };
}
}
/// <summary>
/// Create a group
/// </summary>
/// <param name="groupCreateOrUpdateDetail">Group to create</param>
[ProducesResponseType(typeof(GroupDetailDTO), 200)]
[HttpPost]
public ObjectResult Create([FromBody] GroupCreateOrUpdateDetailDTO groupCreateOrUpdateDetail)
{
try
{
if (groupCreateOrUpdateDetail == null)
throw new KeyNotFoundException("Group is null");
GroupDetailDTO groupCreated = GroupService.CreateOrUpdate(this._GroupDatabaseService, this._DeviceDatabaseService, groupCreateOrUpdateDetail.UserId, groupCreateOrUpdateDetail, true);
return new OkObjectResult(groupCreated);
}
catch (Exception ex)
{
return new ObjectResult(ex.Message) { StatusCode = 500 };
}
}
/// <summary>
/// Create groups from provider
/// </summary>
/// <param name="userId">User Id</param>
[ProducesResponseType(typeof(List<GroupDetailDTO>), 200)]
[HttpPost("{userId}/fromZigbee")]
public ObjectResult CreateDevicesFromZigbee2Mqtt(string userId)
{
try
{
if (userId == null)
throw new InvalidOperationException("User not found");
if (!UserService.IsExist(_UserDatabaseService, userId))
throw new KeyNotFoundException("User not found");
Provider provider = _ProviderDatabaseService.GetByType("zigbee2mqtt");
if (provider == null)
throw new KeyNotFoundException("Zigbee2mqtt provider not found");
// GET ALL LOCAL GROUPS
var groups = MqttClientService.groups; // Be carefull, we only got the exact result after each connection
List<GroupDetailDTO> groupsDetail= GroupService.CreateFromZigbeeAsync(_GroupDatabaseService, _DeviceDatabaseService, userId, groups);
return new OkObjectResult(groupsDetail);
}
catch (Exception ex)
{
return new ObjectResult(ex.Message) { StatusCode = 500 };
}
}
/// <summary>
/// Update a group
/// </summary>
/// <param name="groupCreateOrUpdateDetail">group to update</param>
[ProducesResponseType(typeof(GroupCreateOrUpdateDetailDTO), 200)]
[HttpPut]
public ObjectResult Update([FromBody] GroupCreateOrUpdateDetailDTO groupCreateOrUpdateDetail)
{
try
{
if (!_GroupDatabaseService.IsExist(groupCreateOrUpdateDetail.Id))
throw new KeyNotFoundException("Group does not exist");
GroupDetailDTO groupUpdated = GroupService.CreateOrUpdate(this._GroupDatabaseService, this._DeviceDatabaseService, groupCreateOrUpdateDetail.UserId, groupCreateOrUpdateDetail, false);
return new OkObjectResult(groupUpdated);
}
catch (KeyNotFoundException ex)
{
return new BadRequestObjectResult(ex.Message) { StatusCode = 404 };
}
catch (Exception ex)
{
return new ObjectResult(ex.Message) { StatusCode = 500 };
}
}
/// <summary>
/// Delete device from a group
/// </summary>
/// <param name="deviceId">Id of device to delete from the group</param>
/// <param name="groupId">Id of group </param>
[HttpDelete("{groupId}/device/{deviceId}")]
public ObjectResult Delete(string deviceId, string groupId)
{
try
{
if (groupId != null && deviceId != null)
{
if (_GroupDatabaseService.IsExist(groupId))
{
// Update group
Group group = _GroupDatabaseService.GetById(groupId);
group.DevicesIds = group.DevicesIds.Where(d => d != deviceId).ToList();
group.UpdatedDate = DateTime.Now;
_GroupDatabaseService.Update(group);
// Update device
Device device = _DeviceDatabaseService.GetById(deviceId);
if (device != null)
{
device.GroupIds = device.GroupIds.Where(g => g != groupId).ToList();
device.UpdatedDate = DateTime.Now;
_DeviceDatabaseService.Update(device);
}
}
}
return new OkObjectResult(201);
}
catch (Exception ex)
{
return new ObjectResult(ex.Message) { StatusCode = 500 };
}
}
/// <summary>
/// Delete a group
/// </summary>
/// <param name="groupId">Id of group to delete</param>
[HttpDelete("{groupId}")]
public ObjectResult Delete(string groupId)
{
try
{
if (groupId != null)
{
if (_GroupDatabaseService.IsExist(groupId))
{
Group group = _GroupDatabaseService.GetById(groupId);
// Delete group from all devices
List<Device> devices = _DeviceDatabaseService.GetByLocation(group.UserId, groupId);
foreach (var device in devices)
{
device.GroupIds = device.GroupIds.Where(g => g != groupId).ToList();
device.UpdatedDate = DateTime.Now;
_DeviceDatabaseService.Update(device);
}
// Delete group
_GroupDatabaseService.Remove(groupId);
}
}
return new OkObjectResult(201);
}
catch (Exception ex)
{
return new ObjectResult(ex.Message) { StatusCode = 500 };
}
}
/// <summary>
/// Get all zigbee2Mqtt groups
/// </summary>
/// <param name="userId">User Id</param>
[ProducesResponseType(typeof(List<GroupDetailDTO>), 200)]
[HttpGet("zigbee2Mqtt/{userId}")]
public ObjectResult GetGroupsFromZigbee2Mqtt(string userId)
{
try
{
if (userId == null)
throw new InvalidOperationException("User not found");
if (!UserService.IsExist(_UserDatabaseService, userId))
throw new KeyNotFoundException("User not found");
// GET ALL LOCAL GROUPS
var groups = MqttClientService.groups; // Be carefull, we only got the exact result after each connection
return new OkObjectResult(groups);
}
catch (InvalidOperationException ex)
{
return new BadRequestObjectResult(ex.Message) { StatusCode = 400 };
}
catch (Exception ex)
{
return new ObjectResult(ex.Message) { StatusCode = 500 };
}
}
/// <summary>
/// Delete all group for a specified
/// </summary>
/// <param name="userId">Id of user</param>
[HttpDelete("user/{userId}")]
public ObjectResult DeleteAllForUser(string userId)
{
try
{
if (userId != null)
{
if (_UserDatabaseService.IsExist(userId))
{
_GroupDatabaseService.RemoveForUser(userId);
}
}
return new OkObjectResult(201);
}
catch (Exception ex)
{
return new ObjectResult(ex.Message) { StatusCode = 500 };
}
}
}
}

View File

@ -20,8 +20,10 @@ namespace Mqtt.Client.AspNetCore.Services
private static IMqttClient mqttClient;
private IMqttClientOptions options;
public static List<Zigbee2MqttDevice> devices = new List<Zigbee2MqttDevice>();
public static List<Zigbee2MqttGroup> groups = new List<Zigbee2MqttGroup>();
public static string userId;
static DeviceDatabaseService _deviceDatabaseService;
static GroupDatabaseService _groupDatabaseService;
static ProviderDatabaseService _providerDatabaseService;
static LocationDatabaseService _locationDatabaseService;
static AutomationDatabaseService _automationDatabaseService;
@ -64,28 +66,35 @@ namespace Mqtt.Client.AspNetCore.Services
var topic = e.ApplicationMessage.Topic;
if (_actionService != null) {
ActionService.HandleActionFromMQTTAsync(topic, payload, _deviceDatabaseService, _providerDatabaseService, _locationDatabaseService, _automationDatabaseService, userId);
if (_actionService != null)
{
ActionService.HandleActionFromMQTTAsync(topic, payload, _deviceDatabaseService, _groupDatabaseService, _providerDatabaseService, _locationDatabaseService, _automationDatabaseService, userId);
}
//if () { }
//List<Device> Devices = _DeviceDatabaseService.GetByProviderId(topic);
switch (topic)
{
case "zigbee2mqtt/bridge/config/devices":
try
{
var test = JsonConvert.DeserializeObject<List<Zigbee2MqttDevice>>(payload);
devices = test;
// TODO Update in DB, current devices state
var devicesConvert = JsonConvert.DeserializeObject<List<Zigbee2MqttDevice>>(payload);
devices = devicesConvert;
}
catch (Exception ex)
{
Console.WriteLine($"Error during retrieving devices ! Exception: {ex}");
}
break;
case "zigbee2mqtt/bridge/groups":
try
{
var groupsConvert = JsonConvert.DeserializeObject<List<Zigbee2MqttGroup>>(payload);
groups = groupsConvert;
}
catch (Exception ex)
{
Console.WriteLine($"Error during retrieving groups ! Exception: {ex}");
}
break;
}
//return new Task(null);
@ -152,9 +161,10 @@ namespace Mqtt.Client.AspNetCore.Services
return devices;
}
public static void SetServices(DeviceDatabaseService _DeviceDatabaseService, ProviderDatabaseService _ProviderDatabaseService, LocationDatabaseService _LocationDatabaseService, ActionService _ActionService, AutomationDatabaseService _AutomationDatabaseService, string UserId)
public static void SetServices(DeviceDatabaseService _DeviceDatabaseService, GroupDatabaseService _GroupDatabaseService, ProviderDatabaseService _ProviderDatabaseService, LocationDatabaseService _LocationDatabaseService, ActionService _ActionService, AutomationDatabaseService _AutomationDatabaseService, string UserId)
{
_deviceDatabaseService = _DeviceDatabaseService;
_groupDatabaseService = _GroupDatabaseService;
_providerDatabaseService = _ProviderDatabaseService;
_locationDatabaseService = _LocationDatabaseService;
_automationDatabaseService = _AutomationDatabaseService;

View File

@ -32,7 +32,7 @@ namespace MyCore.Service
/// <summary>
/// Permissions for each type of profile
/// </summary>
public static readonly Dictionary<Type, string[]> ProfilesConfiguration = new Dictionary<Type, string[]>()
public static readonly Dictionary<System.Type, string[]> ProfilesConfiguration = new Dictionary<System.Type, string[]>()
{
// An admin has access to everything
//{ typeof(AdminProfile), new[] { Permissions.Admin} },

View File

@ -2,6 +2,7 @@
using MyCore.Interfaces.DTO;
using MyCore.Interfaces.Models;
using MyCore.Interfaces.Models.Providers.Zigbee.Aqara;
using MyCore.Service.Services;
using MyCore.Services.MyControlPanel;
using Newtonsoft.Json;
using System;
@ -22,19 +23,21 @@ namespace MyCore.Services.Devices
private static dynamic triggerStateName;
private static dynamic triggerStateValueCheck;
// TODO it's here that action are thrown.. Call from Mqtt Or other service like controller if from RpiServices
public static void HandleActionFromMQTTAsync(string topic, string message, DeviceDatabaseService _DeviceDatabaseService, ProviderDatabaseService _ProviderDatabaseService, LocationDatabaseService _LocationDatabaseService, AutomationDatabaseService _AutomationDatabaseService, string userId)
public static void HandleActionFromMQTTAsync(string topic, string message, DeviceDatabaseService _DeviceDatabaseService, GroupDatabaseService _GroupDatabaseService, ProviderDatabaseService _ProviderDatabaseService, LocationDatabaseService _LocationDatabaseService, AutomationDatabaseService _AutomationDatabaseService, string userId)
{
// TODO Check if two action from the same device ar not too closed (!! motion (F => T) and switch (action and click = same)
// TODO Check if two action from the same device ar not too closed (!! motion (F => T) and switch (action and click = same) // just update if action is different in case of true false action
var actionTime = DateTimeOffset.Now.ToUnixTimeMilliseconds();
var providers = _ProviderDatabaseService.GetAll(userId);
string[] topicSplit = topic.Split('/');
UpdateZigbee2MqttConfigAsync(topic, message, userId, _DeviceDatabaseService, _GroupDatabaseService, _ProviderDatabaseService, _LocationDatabaseService);
System.Console.WriteLine($"Received message {message}");
switch (topicSplit[0]) {
case "zigbee2mqtt":
var test0 = _ProviderDatabaseService.GetByType(topicSplit[0]).Id;
var automations = _AutomationDatabaseService.GetByProvider(test0);
var provider = _ProviderDatabaseService.GetByType(topicSplit[0]).Id;
var automations = _AutomationDatabaseService.GetByProvider(provider);
var serviceName = topicSplit[1];
var zigbeeDevice = _DeviceDatabaseService.GetByName(serviceName).FirstOrDefault();
@ -54,6 +57,10 @@ namespace MyCore.Services.Devices
deserializedReceivedMessage = JsonConvert.DeserializeObject<LightBulb>(message);
zigbeeDevice.LastState = message;
break;
case DeviceType.Motion:
deserializedReceivedMessage = JsonConvert.DeserializeObject<AqaraMotion>(message);
zigbeeDevice.LastState = message;
break;
case DeviceType.Plug:
zigbeeDevice.LastState = message;
break;
@ -76,13 +83,13 @@ namespace MyCore.Services.Devices
System.Console.WriteLine($"Open automation {automation.Name}");
var automationTrigger = automation.Triggers.Where(t => t.DeviceId == zigbeeDevice.Id).FirstOrDefault();
Type type = deserializedReceivedMessage.GetType();
System.Type type = deserializedReceivedMessage.GetType();
PropertyInfo property = type.GetProperty(automationTrigger.StateName);
triggerStateValueCheck = property.GetValue(deserializedReceivedMessage);
triggerStateName = property.Name;
// Todo check state name and value for triggers..
if (automationTrigger.StateName == triggerStateName && automationTrigger.StateValue == triggerStateValueCheck)
if (automationTrigger.StateName == triggerStateName && automationTrigger.StateValue == triggerStateValueCheck.ToString())
{
// Todo check condition
if (automation.Conditions.Count <= 0)
@ -95,11 +102,39 @@ namespace MyCore.Services.Devices
var stateName = action.StateName;
var stateValue = action.StateValue;
var zigbeeDeviceAction = _DeviceDatabaseService.GetById(action.DeviceId);
var providerAction = _ProviderDatabaseService.GetById(userId, zigbeeDeviceAction.ProviderId);
var actionName = "";
Device actionDeviceToTest = new Device();
switch (action.Type) {
case Interfaces.Models.Type.DEVICE:
var zigbeeDeviceAction = _DeviceDatabaseService.GetById(action.DeviceId);
var providerActionTest = _ProviderDatabaseService.GetById(userId, action.ProviderId);
actionName = zigbeeDeviceAction.Name;
actionDeviceToTest = zigbeeDeviceAction;
System.Console.WriteLine($"We get a zigbeeDeviceAction ! Name={zigbeeDeviceAction.Name} Type={zigbeeDeviceAction.Type}");
System.Console.WriteLine($"Check action provider type ! Type={providerAction.Type} Name={providerAction.Name}");
System.Console.WriteLine($"Check action provider type ! Type={providerActionTest.Type} Name={providerActionTest.Name}");
break;
case Interfaces.Models.Type.GROUP:
var zigbeeGroupAction = _GroupDatabaseService.GetById(action.GroupId);
actionName = zigbeeGroupAction.Name;
System.Console.WriteLine($"We get a zigbeeGroupAction ! Name={zigbeeGroupAction.Name} Type={zigbeeGroupAction.Type}");
System.Console.WriteLine($"Check action zigbeeGroupAction type ! Type={zigbeeGroupAction.Type}");
// Check state of first device of a group
actionDeviceToTest = _DeviceDatabaseService.GetByGroup(zigbeeGroupAction.Id).FirstOrDefault(); // TODO : Send error if no device found !
break;
case Interfaces.Models.Type.MQTT: // Correct way ?
// TODO
//requestType = Interfaces.Models.Type.MQTT;
break;
case Interfaces.Models.Type.HTTP: // Correct way ?
// TODO
break;
}
var providerAction = _ProviderDatabaseService.GetById(userId, action.ProviderId);
switch (providerAction.Type)
{
@ -107,14 +142,14 @@ namespace MyCore.Services.Devices
Zigbee2MqttRequest zigbee2MqttRequest = new Zigbee2MqttRequest() { };
var actionRequest = "";
System.Console.WriteLine($"Zigbee type !");
System.Console.WriteLine($"zigbee2mqtt type !");
// Todo GET AND CHECK DEVICE ACTION POSSIBLE
// todo check state name (state, action.. )
System.Console.WriteLine($"zigbeeDeviceAction.Type {zigbeeDeviceAction.Type}");
if (zigbeeDeviceAction.Type == DeviceType.Light)
System.Console.WriteLine($"actionDeviceToTest.Type {actionDeviceToTest.Type}");
if (actionDeviceToTest.Type == DeviceType.Light)
{
var deserializedReceivedMessage2 = JsonConvert.DeserializeObject<LightBulb>(zigbeeDeviceAction.LastState);
var deserializedReceivedMessage2 = JsonConvert.DeserializeObject<LightBulb>(actionDeviceToTest.LastState);
if (stateValue == DeviceAction.toggle.ToString())
{
@ -134,23 +169,29 @@ namespace MyCore.Services.Devices
break;
}
}
else if (stateValue == DeviceAction.on.ToString()) {
actionRequest = "ON";
zigbee2MqttRequest.brightness = 255;
} else {
// DeviceAction.off.ToString() => Need to ad validation ?
actionRequest = "OFF";
zigbee2MqttRequest.brightness = 0;
}
}
System.Console.WriteLine($"Before retrieving type etc {zigbee2MqttRequest.state}");
Type type2 = zigbee2MqttRequest.GetType();
System.Type type2 = zigbee2MqttRequest.GetType();
PropertyInfo property2 = type2.GetProperty(stateName);
property2.SetValue(zigbee2MqttRequest, actionRequest, null);
var request = JsonConvert.SerializeObject(zigbee2MqttRequest);
var name = zigbeeDeviceAction.Name.Substring(0, zigbeeDeviceAction.Name.Length - 1); // TODO CHANGE !!!!
System.Console.WriteLine($"Send request ! zigbee2mqtt/{actionName}/set/{request}");
System.Console.WriteLine($"Send request ! zigbee2mqtt/{name}/set/{request}");
MqttClientService.PublishMessage("zigbee2mqtt/" + name + "/set", request);
MqttClientService.PublishMessage("zigbee2mqtt/" + actionName + "/set", request);
break;
case "meross":
System.Console.WriteLine($"meross type !");
break;
}
}
@ -191,8 +232,8 @@ namespace MyCore.Services.Devices
}*/
if (test.action == "tap")
{
var provider = providers.Where(p => p.Type == "meross").FirstOrDefault();
var merossDevices = _DeviceDatabaseService.GetByProviderId(provider.Id);
var merossProvider = providers.Where(p => p.Type == "meross").FirstOrDefault();
var merossDevices = _DeviceDatabaseService.GetByProviderId(merossProvider.Id);
var multiprise = merossDevices.Where(md => md.Name == "Multiprise bureau").FirstOrDefault();
//var prise = merossDevices.Where(md => md.Name == "Imprimante 3D").FirstOrDefault();
@ -275,5 +316,56 @@ namespace MyCore.Services.Devices
break;
}
}
public static async Task UpdateZigbee2MqttConfigAsync(string topic, string message, string userId, DeviceDatabaseService _DeviceDatabaseService, GroupDatabaseService _GroupDatabaseService, ProviderDatabaseService _ProviderDatabaseService, LocationDatabaseService _LocationDatabaseService) {
// update zigbee2mqqtt config
switch (topic)
{
case "zigbee2mqtt/bridge/config/devices":
try
{
var devices = JsonConvert.DeserializeObject<List<Zigbee2MqttDevice>>(message);
var zigbee2mqttProvider = _ProviderDatabaseService.GetByType("zigbee2mqtt");
if (zigbee2mqttProvider != null)
{
// Retrieve existing devices
List<Device> existingDevices = _DeviceDatabaseService.GetByProviderId(zigbee2mqttProvider.Id);
var existingDevicesAddresses = existingDevices.Select(ed => ed.ServiceIdentification);
// Filter devices and check if something new
var filteredDevices = devices.Where(d => !existingDevicesAddresses.Contains(d.ieeeAddr)).ToList();
// Add new devices
Dictionary<string, List<DeviceDetailDTO>> createdDevices = await DeviceService.CreateFromZigbeeAsync(_DeviceDatabaseService, _ProviderDatabaseService, _LocationDatabaseService, userId, filteredDevices, zigbee2mqttProvider);
}
System.Console.WriteLine($"Devices updated for user {userId}");
}
catch (Exception ex)
{
Console.WriteLine($"Error during retrieving devices ! Exception: {ex}");
}
break;
case "zigbee2mqtt/bridge/groups":
try
{
var groupsConvert = JsonConvert.DeserializeObject<List<Zigbee2MqttGroup>>(message);
var zigbee2mqttProvider = _ProviderDatabaseService.GetByType("zigbee2mqtt");
if (zigbee2mqttProvider != null)
{
var groups = _GroupDatabaseService.GetByType(userId, "zigbee2mqtt");
// Compare the groups from MyCore and the group we received, if something diff in one group => Hard refresh (delete, new)
GroupService.CompareGroupsFromZigbee2Mqtt(userId, groups, groupsConvert, _DeviceDatabaseService, _GroupDatabaseService);
}
}
catch (Exception ex)
{
Console.WriteLine($"Error during retrieving groups ! Exception: {ex}");
}
break;
}
}
}
}

View File

@ -0,0 +1,147 @@
using MyCore.Interfaces.DTO;
using MyCore.Interfaces.Models;
using MyCore.Services.MyControlPanel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace MyCore.Service.Services
{
public class GroupService
{
public static GroupDetailDTO CreateOrUpdate(GroupDatabaseService _GroupDatabaseService, DeviceDatabaseService _DeviceDatabaseService, string userId, GroupCreateOrUpdateDetailDTO groupCreateOrUpdateDetailDTO, bool create)
{
List<Device> devices = new List<Device>();
Group group;
if (create)
{
group = new Group();
group.CreatedDate = DateTime.Now;
group.DevicesIds = new List<string>();
}
else
{
group = _GroupDatabaseService.GetById(groupCreateOrUpdateDetailDTO.Id);
}
group.UserId = userId;
group.Name = groupCreateOrUpdateDetailDTO.Name;
group.Type = group.Type; // TODO
group.UpdatedDate = DateTime.Now;
group.DevicesIds.AddRange(groupCreateOrUpdateDetailDTO.DeviceIds);
if (create)
{
group = _GroupDatabaseService.Create(group);
}
else
{
group = _GroupDatabaseService.Update(group);
}
foreach (var deviceId in groupCreateOrUpdateDetailDTO.DeviceIds)
{
Device device = _DeviceDatabaseService.GetById(deviceId);
devices.Add(device);
device.GroupIds.Add(group.Id);
_DeviceDatabaseService.Update(device);
}
return group.ToDTO(devices.Select(d => d.ToDTO()).ToList());
}
public static List<GroupDetailDTO> CreateFromZigbeeAsync(GroupDatabaseService _GroupDatabaseService, DeviceDatabaseService _DeviceDatabaseService, string userId, List<Zigbee2MqttGroup> zigbee2MqttGroups)
{
List<GroupDetailDTO> groups = new List<GroupDetailDTO>();
foreach (var zigbee2MqttGroup in zigbee2MqttGroups.Where(z => z.members.Count > 0)) // Only take group with members
{
List<Device> devices = new List<Device>();
Group group;
group = new Group();
group.CreatedDate = DateTime.Now;
group.DevicesIds = new List<string>();
group.UserId = userId;
group.Name = zigbee2MqttGroup.friendly_name;
group.Type = "zigbee2mqtt";
group.UpdatedDate = DateTime.Now;
foreach (var member in zigbee2MqttGroup.members)
{
Device device = _DeviceDatabaseService.GetByServiceIdentification(member.ieee_address);
if (device != null) {
group.DevicesIds.Add(device.Id);
}
}
group = _GroupDatabaseService.Create(group);
foreach (var deviceId in group.DevicesIds)
{
Device device = _DeviceDatabaseService.GetById(deviceId);
devices.Add(device);
if (device.GroupIds == null)
device.GroupIds = new List<string>();
device.GroupIds.Add(group.Id);
_DeviceDatabaseService.Update(device);
}
groups.Add(group.ToDTO(devices.Select(d => d.ToDTO()).ToList()));
}
return groups;
}
// We only go in this method if the group config change during operation
public static void CompareGroupsFromZigbee2Mqtt(string userId, List<Group> groups, List<Zigbee2MqttGroup> zigbee2MqttGroups, DeviceDatabaseService _DeviceDatabaseService, GroupDatabaseService _GroupDatabaseService)
{
// We do not refresh all list as we don't want to create plenty of new groupId and have to delete from device param everytime
List<Zigbee2MqttGroup> existingGroups = new List<Zigbee2MqttGroup>();
foreach (var group in groups)
{
var devicesFromGroup = _DeviceDatabaseService.GetByGroup(group.Id);
// convert existing group to zigbee2mqtt group
existingGroups.Add(new Zigbee2MqttGroup { friendly_name = group.Name, id = group.ServiceIdentification, members = devicesFromGroup.Select(d => new Member() { ieee_address = d.ServiceIdentification }).ToList() }); ;
}
foreach (var zigbee2MqttGroup in zigbee2MqttGroups)
{
var existingGroupWithThisId = existingGroups.Where(eg => eg.id == zigbee2MqttGroup.id).ToList().FirstOrDefault();
if (existingGroupWithThisId == null)
{
// New group -> Create it !
CreateFromZigbeeAsync(_GroupDatabaseService, _DeviceDatabaseService, userId, zigbee2MqttGroups.Where(z => z.id == zigbee2MqttGroup.id).ToList());
} else {
if (!Enumerable.SequenceEqual(zigbee2MqttGroup.members.Select(m => m.ieee_address).OrderBy(t => t), existingGroupWithThisId.members.Select(m => m.ieee_address).OrderBy(t => t)))
{
// different ? Update
// As user not change everytime.. => Hard refresh.
var groupToDelete = groups.Where(eg => eg.ServiceIdentification == existingGroupWithThisId.id).FirstOrDefault();
// Delete in device first
var devicesInGroup = _DeviceDatabaseService.GetByGroup(groupToDelete.Id);
foreach (var device in devicesInGroup)
{
device.GroupIds = device.GroupIds.Where(g => g != groupToDelete.Id).ToList();
_DeviceDatabaseService.Update(device);
}
// Delete group
_GroupDatabaseService.Remove(groupToDelete.Id);
// Create new group
CreateFromZigbeeAsync(_GroupDatabaseService, _DeviceDatabaseService, userId, new List<Zigbee2MqttGroup>() { zigbee2MqttGroup });
}
}
// else do nothing
}
}
}
}

View File

@ -29,6 +29,11 @@ namespace MyCore.Services.MyControlPanel
return _Devices.Find<Device>(d => d.Id == id).FirstOrDefault();
}
public Device GetByServiceIdentification(string serviceIdentification)
{
return _Devices.Find<Device>(d => d.ServiceIdentification == serviceIdentification).FirstOrDefault();
}
public List<Device> GetByIds(List<string> ids)
{
return _Devices.Find<Device>(d => ids.Contains(d.Id)).ToList();
@ -49,6 +54,11 @@ namespace MyCore.Services.MyControlPanel
return _Devices.Find(d => d.ProviderId == providerId).ToList();
}
public List<Device> GetByGroup(string groupId)
{
return _Devices.Find(d => d.GroupIds.Contains(groupId)).ToList();
}
public List<Device> GetByName(string name)
{
return _Devices.Find(d => d.Name == name).ToList();

View File

@ -18,14 +18,25 @@ namespace MyCore.Services.MyControlPanel
var database = client.GetDatabase("MyCoreDb");
_Groups = database.GetCollection<Group>("Groups");
}
public List<Group> GetAll()
public List<Group> GetAll(string userId)
{
return _Groups.Find(d => true).ToList();
return _Groups.Find(d => d.UserId == userId).ToList();
}
public Group GetById(string id)
{
return _Groups.Find<Group>(g => g.Id == id).FirstOrDefault();
return _Groups.Find<Group>(d => d.Id == id).FirstOrDefault();
}
public List<Group> GetByType(string userId, string type)
{
return _Groups.Find(d => d.UserId == userId && d.Type == type).ToList();
}
public bool IsExist(string id)
{
return _Groups.Find<Group>(d => d.Id == id).FirstOrDefault() != null ? true : false;
}
public Group Create(Group group)
@ -34,9 +45,9 @@ namespace MyCore.Services.MyControlPanel
return group;
}
public Group Update(string id, Group groupIn)
public Group Update(Group groupIn)
{
_Groups.ReplaceOne(group => group.Id == id, groupIn);
_Groups.ReplaceOne(room => room.Id == groupIn.Id, groupIn);
return groupIn;
}
@ -44,5 +55,10 @@ namespace MyCore.Services.MyControlPanel
{
_Groups.DeleteOne(group => group.Id == id);
}
public void RemoveForUser(string userId)
{
_Groups.DeleteMany(group => group.UserId == userId);
}
}
}

View File

@ -199,6 +199,7 @@ namespace MyCore
services.AddScoped<UserDatabaseService>();
services.AddScoped<ProviderDatabaseService>();
services.AddScoped<DeviceDatabaseService>();
services.AddScoped<GroupDatabaseService>();
services.AddScoped<LocationDatabaseService>();
services.AddScoped<AutomationDatabaseService>();
services.AddScoped<ActionService>();