MC update group controller + update action service (no more type var WIP) + clean code

This commit is contained in:
Thomas Fransolet 2021-03-17 18:11:29 +01:00
parent 461c998bb6
commit 764fcfe414
5 changed files with 282 additions and 117 deletions

View File

@ -45,10 +45,10 @@ namespace MyCore.Interfaces.Models
public string model { get; set; } public string model { get; set; }
public bool supports_ota { get; set; } public bool supports_ota { get; set; }
public string vendor { get; set; } public string vendor { get; set; }
public List<Exposes> exposes { get; set; } public List<Expose> exposes { get; set; }
} }
public class Exposes { public class Expose {
public int access { get; set; } public int access { get; set; }
public string description { get; set; } public string description { get; set; }
public string name { get; set; } public string name { get; set; }
@ -58,8 +58,9 @@ namespace MyCore.Interfaces.Models
public List<string> values { get; set; } // if enum public List<string> values { get; set; } // if enum
public bool value_on { get; set; } // if binary public object value_on { get; set; } // if binary
public bool value_off { get; set; } // if binary public object value_off { get; set; } // if binary
public object value_toggle { get; set; } // if binary
public int value_max { get; set; } // if numeric public int value_max { get; set; } // if numeric
public int value_min { get; set; } // if numeric public int value_min { get; set; } // if numeric
@ -76,9 +77,9 @@ namespace MyCore.Interfaces.Models
public string property { get; set; } public string property { get; set; }
public string type { get; set; } // numeric, binary, enum, light public string type { get; set; } // numeric, binary, enum, light
public string value_on { get; set; } // if binary public object value_on { get; set; } // if binary
public string value_off { get; set; } // if binary public object value_off { get; set; } // if binary
public string value_toggle { get; set; } // if binary public object value_toggle { get; set; } // if binary
public int value_max { get; set; } // if numeric public int value_max { get; set; } // if numeric
public int value_min { get; set; } // if numeric public int value_min { get; set; } // if numeric

View File

@ -76,6 +76,9 @@ namespace MyCore.Service.Controllers
if (userId != null && groupId != null) if (userId != null && groupId != null)
{ {
Group group = _GroupDatabaseService.GetById(groupId); Group group = _GroupDatabaseService.GetById(groupId);
if (group == null)
throw new KeyNotFoundException("Group not found");
List<Device> devices = _DeviceDatabaseService.GetByLocation(group.UserId, groupId); List<Device> devices = _DeviceDatabaseService.GetByLocation(group.UserId, groupId);
return new OkObjectResult(group.ToDTO(devices.Select(d => d.ToDTO()).ToList())); return new OkObjectResult(group.ToDTO(devices.Select(d => d.ToDTO()).ToList()));
@ -85,6 +88,10 @@ namespace MyCore.Service.Controllers
return new ObjectResult("Invalid parameters") { StatusCode = 400 }; return new ObjectResult("Invalid parameters") { StatusCode = 400 };
} }
} }
catch (KeyNotFoundException ex)
{
return new BadRequestObjectResult(ex.Message) { StatusCode = 404 };
}
catch (Exception ex) catch (Exception ex)
{ {
return new ObjectResult(ex.Message) { StatusCode = 500 }; return new ObjectResult(ex.Message) { StatusCode = 500 };

View File

@ -28,9 +28,19 @@ namespace MyCore.Service.Services
automation.Conditions = automationCreateOrUpdateDetailDTO.Conditions; automation.Conditions = automationCreateOrUpdateDetailDTO.Conditions;
automation.Actions = automationCreateOrUpdateDetailDTO.Actions; automation.Actions = automationCreateOrUpdateDetailDTO.Actions;
var allDeviceIds = new List<string>(); var allDeviceIds = new List<string>();
allDeviceIds.AddRange(automation.Triggers.Select(t => t.DeviceId)); allDeviceIds.AddRange(automation.Triggers.Select(t => t.DeviceId)); // Only take the deviceIds from triggers
allDeviceIds.AddRange(automation.Conditions.Select(t => t.DeviceId)); /*allDeviceIds.AddRange(automation.Conditions.Select(t => t.DeviceId));
allDeviceIds.AddRange(automation.Actions.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; automation.DevicesIds = allDeviceIds;
if (create) if (create)

View File

@ -18,9 +18,9 @@ namespace MyCore.Services.Devices
{ {
public static bool isOpen = false; public static bool isOpen = false;
public static long lastActionTime; public static long lastActionTime;
private static dynamic deserializedReceivedMessage; //private static dynamic deserializedReceivedMessage;
private static dynamic triggerStateName; //private static dynamic triggerStateName;
private static dynamic triggerStateValueCheck; //private static dynamic triggerStateValueCheck;
public static void HandleActionFromMQTTAsync(string topic, string message, DeviceDatabaseService _DeviceDatabaseService, GroupDatabaseService _GroupDatabaseService, 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)
{ {
@ -48,6 +48,7 @@ namespace MyCore.Services.Devices
try try
{ {
/*
// Todo Deserialize by type // Todo Deserialize by type
switch (zigbeeDevice.Type) switch (zigbeeDevice.Type)
{ {
@ -68,14 +69,11 @@ namespace MyCore.Services.Devices
break; break;
default: default:
break; break;
} }*/
// if is not a set => check automation // if is not a set => check automation
if (topicSplit.Length <= 2) if (topicSplit.Length <= 2)
{ {
zigbeeDevice.LastStateDate = DateTime.Now;
_DeviceDatabaseService.Update(zigbeeDevice);
foreach (var automation in automations) foreach (var automation in automations)
{ {
@ -85,13 +83,31 @@ namespace MyCore.Services.Devices
System.Console.WriteLine($"Open automation {automation.Name}"); System.Console.WriteLine($"Open automation {automation.Name}");
var automationTrigger = automation.Triggers.Where(t => t.DeviceId == zigbeeDevice.Id).FirstOrDefault(); var automationTrigger = automation.Triggers.Where(t => t.DeviceId == zigbeeDevice.Id).FirstOrDefault();
System.Type type = deserializedReceivedMessage.GetType(); List<Expose> exposes = GetDeviceExposes(zigbeeDevice);
PropertyInfo property = type.GetProperty(automationTrigger.StateName);
triggerStateValueCheck = property.GetValue(deserializedReceivedMessage);
triggerStateName = property.Name;
if (automationTrigger.StateName == triggerStateName && automationTrigger.StateValue.ToLower() == triggerStateValueCheck.ToString().ToLower()) 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
//System.Type typeToCheck = GetStateType(expose);
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 !
// Todo check condition // Todo check condition
if (automation.Conditions.Count <= 0) if (automation.Conditions.Count <= 0)
{ {
@ -136,89 +152,145 @@ namespace MyCore.Services.Devices
var providerAction = _ProviderDatabaseService.GetById(userId, action.ProviderId); var providerAction = _ProviderDatabaseService.GetById(userId, action.ProviderId);
// Check if device exist
if (actionDeviceToTest != null)
{
switch (providerAction.Type) switch (providerAction.Type)
{ {
case "zigbee2mqtt": case "zigbee2mqtt":
Zigbee2MqttRequest zigbee2MqttRequest = new Zigbee2MqttRequest() { }; //Zigbee2MqttRequest zigbee2MqttRequest = new Zigbee2MqttRequest() { };
var actionRequest = ""; var request = "";
// If the state is already good, do not send the request. (in order to not spam mqtt broker) // If the state is already good, do not send the request. (in order to not spam mqtt broker)
bool alreadyInAskedState = false; bool alreadyInAskedState = false;
System.Console.WriteLine($"zigbee2mqtt type !"); System.Console.WriteLine($"zigbee2mqtt type !");
// TODO: GET AND CHECK DEVICE ACTION POSSIBILITIES var actionDeviceExpose = GetDeviceExposes(actionDeviceToTest);
// TODO: Check state name (state, action.. ) bool validAction = false;
System.Console.WriteLine($"actionDeviceToTest.Type {actionDeviceToTest.Type}");
// TODO: Check if switch correct and if we can toggle => Same for Plug etc (depend on request)
// TODO: Check if device has brightness possibility..
if (actionDeviceToTest.Type == DeviceType.Light || actionDeviceToTest.Type == DeviceType.Switch) if (actionDeviceToTest.Type == DeviceType.Light || actionDeviceToTest.Type == DeviceType.Switch)
{ {
var deserializedLastState = JsonConvert.DeserializeObject<LightBulb>(actionDeviceToTest.LastState); var typeToTest = actionDeviceToTest.Type == DeviceType.Light ? "light" : "switch";
var exposeToTest = actionDeviceExpose.Where(e => e.type == typeToTest).FirstOrDefault();
validAction = exposeToTest != null;
}
else {
// Retrieve exposes for actionDevice
var exposeToTest = actionDeviceExpose.Where(e => e.name == action.StateName).FirstOrDefault();
validAction = exposeToTest != null;
}
if (stateValue == DeviceAction.toggle.ToString()) if (validAction)
{
var dic = new Dictionary<string, object>();
if (actionDeviceToTest.LastState != null) {
dic = JsonConvert.DeserializeObject<Dictionary<string, object>>(actionDeviceToTest.LastState);
}
// TODO: Check if switch correct and if we can toggle => Same for Plug etc (depend on request)
// TODO: Check if device has brightness possibility..
bool isBrightness = false;
if (actionDeviceToTest.Type == DeviceType.Light || actionDeviceToTest.Type == DeviceType.Switch)
{
var requestBefore = new Dictionary<string, object>();
requestBefore.Add(action.StateName, action.StateValue);
request = JsonConvert.SerializeObject(requestBefore);
if (dic.Count > 0) {
if (dic["state"].ToString().ToLower() == stateValue.ToLower())
{
alreadyInAskedState = true;
}
}
/*if (stateValue == DeviceAction.toggle.ToString())
{ {
System.Console.WriteLine($"Toggle action"); System.Console.WriteLine($"Toggle action");
// TO CHECK // TODO => Check exposes device etc
switch (deserializedLastState.state) switch (dic["state"].ToLower())
{ {
case "ON": case "on":
actionRequest = "OFF"; actionRequest = "off";
zigbee2MqttRequest.brightness = 0; zigbee2MqttRequest.brightness = 0;
break; break;
case "OFF": case "off":
case null: case null:
default: default:
actionRequest = "ON"; actionRequest = "on";
zigbee2MqttRequest.brightness = 255; zigbee2MqttRequest.brightness = 255;
break; break;
} }
} }
else if (stateValue.ToLower() == DeviceAction.on.ToString().ToLower()) { else if (stateValue.ToLower() == DeviceAction.on.ToString().ToLower())
{
// retrieve device state to check if already in asked state // retrieve device state to check if already in asked state
if (deserializedLastState.state.ToLower() == stateValue.ToLower()) if (dic["state"].ToLower() == stateValue.ToLower())
alreadyInAskedState = true;
else {
actionRequest = "ON";
zigbee2MqttRequest.brightness = 255;
}
} else {
// DeviceAction.off.ToString() => Need to ad validation ?
// retrieve device state to check if already in asked state
if (deserializedLastState.state.ToLower() == stateValue.ToLower())
alreadyInAskedState = true; alreadyInAskedState = true;
else else
{ {
actionRequest = "OFF"; actionRequest = "on";
zigbee2MqttRequest.brightness = 255;
}
}
else
{
// DeviceAction.off.ToString() => Need to ad validation ?
// retrieve device state to check if already in asked state
if (dic["state"].ToLower() == stateValue.ToLower())
alreadyInAskedState = true;
else
{
actionRequest = "off";
zigbee2MqttRequest.brightness = 0; zigbee2MqttRequest.brightness = 0;
} }
} }*/
} }
if (!alreadyInAskedState) { if (!alreadyInAskedState)
System.Console.WriteLine($"Before retrieving type etc {zigbee2MqttRequest.state}"); {
/*System.Console.WriteLine($"Before retrieving type etc {zigbee2MqttRequest.state}");
System.Type type2 = zigbee2MqttRequest.GetType(); System.Type type2 = zigbee2MqttRequest.GetType();
PropertyInfo property2 = type2.GetProperty(stateName); PropertyInfo property2 = type2.GetProperty(stateName);
property2.SetValue(zigbee2MqttRequest, actionRequest, null); property2.SetValue(zigbee2MqttRequest, actionRequest, null);
var request = JsonConvert.SerializeObject(zigbee2MqttRequest); var request = JsonConvert.SerializeObject(zigbee2MqttRequest);*/
var requestToSend = $"Send request ! zigbee2mqtt/{actionName}/set/{request}";
System.Console.WriteLine($"Send request ! zigbee2mqtt/{actionName}/set/{request}"); System.Console.WriteLine($"Send request ! zigbee2mqtt/{actionName}/set/{request}");
MqttClientService.PublishMessage("zigbee2mqtt/" + actionName + "/set", request); MqttClientService.PublishMessage("zigbee2mqtt/" + actionName + "/set", request);
} }
}
else {
// No expose found.. => the device has not the correct state => not correct automation
System.Console.WriteLine($"Invalid action - the request was not sent");
}
break; break;
case "meross": case "meross":
System.Console.WriteLine($"meross type !"); System.Console.WriteLine($"meross type !");
break; break;
} }
} }
else {
System.Console.WriteLine($"Device or group found in action incorrect");
} }
} }
} }
} }
} }
}
zigbeeDevice.LastStateDate = DateTime.Now;
zigbeeDevice.LastState = message;
_DeviceDatabaseService.Update(zigbeeDevice);
}
else else
{ {
// do nothing is a set // do nothing is a set
@ -301,6 +373,59 @@ namespace MyCore.Services.Devices
} }
} }
private static List<Expose> GetDeviceExposes(Device device)
{
List<Expose> exposes = new List<Expose>();
// Get Exposes for the zigbee device
foreach (var supportedOperation in device.SupportedOperations)
{
exposes.Add(JsonConvert.DeserializeObject<Expose>(supportedOperation));
}
return exposes;
}
private static System.Type GetStateType(Expose expose)
{
switch (expose.type)
{
// e.g.: occupancy
case "binary":
if (expose.value_toggle == null)
{
// value are boolean
return true.GetType();
}
else
{
// value are string
return "".GetType();
}
case "numeric":
return new long().GetType();
case "enum":
return expose.values.GetType();
break;
/*case "text":
break;
case "light":
break;
case "composite":
break;
case "switch":
break;*/
/*case "fan":
break;
case "cover":
break;
case "lock":
break;
case "climate":
break;*/
default:
return null;
}
}
public static async Task UpdateZigbee2MqttConfigAsync(string topic, string message, string userId, DeviceDatabaseService _DeviceDatabaseService, GroupDatabaseService _GroupDatabaseService, ProviderDatabaseService _ProviderDatabaseService, LocationDatabaseService _LocationDatabaseService) { public static async Task UpdateZigbee2MqttConfigAsync(string topic, string message, string userId, DeviceDatabaseService _DeviceDatabaseService, GroupDatabaseService _GroupDatabaseService, ProviderDatabaseService _ProviderDatabaseService, LocationDatabaseService _LocationDatabaseService) {
// update zigbee2mqqtt config // update zigbee2mqqtt config
switch (topic) switch (topic)

View File

@ -55,8 +55,28 @@ namespace MyCore.Service.Services
{ {
List<GroupDetailDTO> groups = new List<GroupDetailDTO>(); List<GroupDetailDTO> groups = new List<GroupDetailDTO>();
// Get zigbee groups
List<Group> existingGroups = _GroupDatabaseService.GetByType(userId, "zigbee2mqtt");
foreach (var zigbee2MqttGroup in zigbee2MqttGroups.Where(z => z.members.Count > 0)) // Only take group with members foreach (var zigbee2MqttGroup in zigbee2MqttGroups.Where(z => z.members.Count > 0)) // Only take group with members
{ {
bool create = true;
if (existingGroups.Any(eg => eg.ServiceIdentification == zigbee2MqttGroup.id))
{
var existingGroup = existingGroups.Where(eg => eg.ServiceIdentification == zigbee2MqttGroup.id).FirstOrDefault();
GroupCreateOrUpdateDetailDTO groupToUpdate = new GroupCreateOrUpdateDetailDTO();
groupToUpdate.UserId = existingGroup.UserId;
groupToUpdate.Name = existingGroup.Name;
groupToUpdate.Id = existingGroup.Id;
groupToUpdate.IsAlarm = existingGroup.IsAlarm;
groupToUpdate.DeviceIds = existingGroup.DevicesIds;
// Hard refresh
CreateOrUpdate(_GroupDatabaseService, _DeviceDatabaseService, userId, groupToUpdate, false);
create = false;
}
if (create) {
List<Device> devices = new List<Device>(); List<Device> devices = new List<Device>();
Group group; Group group;
@ -72,7 +92,8 @@ namespace MyCore.Service.Services
foreach (var member in zigbee2MqttGroup.members) foreach (var member in zigbee2MqttGroup.members)
{ {
Device device = _DeviceDatabaseService.GetByServiceIdentification(member.ieee_address); Device device = _DeviceDatabaseService.GetByServiceIdentification(member.ieee_address);
if (device != null) { if (device != null)
{
group.DevicesIds.Add(device.Id); group.DevicesIds.Add(device.Id);
} }
} }
@ -91,6 +112,7 @@ namespace MyCore.Service.Services
groups.Add(group.ToDTO(devices.Select(d => d.ToDTO()).ToList())); groups.Add(group.ToDTO(devices.Select(d => d.ToDTO()).ToList()));
} }
}
return groups; return groups;
} }