using Mqtt.Client.AspNetCore.Services; 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; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Threading.Tasks; using static Mqtt.Client.AspNetCore.Services.MqttClientMerossService; namespace MyCore.Services.Devices { public class ActionService { public static bool isOpen = false; public static long lastActionTime; private static dynamic deserializedReceivedMessage; private static dynamic triggerStateName; private static dynamic triggerStateValueCheck; public static void HandleActionFromMQTTAsync(string topic, string message, DeviceDatabaseService _DeviceDatabaseService, GroupDatabaseService _GroupDatabaseService, ProviderDatabaseService _ProviderDatabaseService, LocationDatabaseService _LocationDatabaseService, AutomationDatabaseService _AutomationDatabaseService, string userId) { var actionTime = DateTimeOffset.Now.ToUnixTimeMilliseconds(); var providers = _ProviderDatabaseService.GetAll(userId); string[] topicSplit = topic.Split('/'); var providerFromTopic = topicSplit[0]; // TODO Sortir automation d'un type specific.. et créer un objet ? System.Console.WriteLine($"Received message {message}"); switch (providerFromTopic) { case "zigbee2mqtt": UpdateZigbee2MqttConfigAsync(topic, message, userId, _DeviceDatabaseService, _GroupDatabaseService, _ProviderDatabaseService, _LocationDatabaseService); var provider = _ProviderDatabaseService.GetByType(topicSplit[0]).Id; var automations = _AutomationDatabaseService.GetByProvider(provider); var serviceName = topicSplit[1]; var zigbeeDevice = _DeviceDatabaseService.GetByName(serviceName).FirstOrDefault(); if (zigbeeDevice != null) { try { // Todo Deserialize by type switch (zigbeeDevice.Type) { case DeviceType.Switch: deserializedReceivedMessage = JsonConvert.DeserializeObject(message); zigbeeDevice.LastState = message; break; case DeviceType.Light: deserializedReceivedMessage = JsonConvert.DeserializeObject(message); zigbeeDevice.LastState = message; break; case DeviceType.Motion: deserializedReceivedMessage = JsonConvert.DeserializeObject(message); zigbeeDevice.LastState = message; break; case DeviceType.Plug: zigbeeDevice.LastState = message; break; default: break; } // if is not a set => check automation if (topicSplit.Length <= 2) { zigbeeDevice.LastStateDate = DateTime.Now; _DeviceDatabaseService.Update(zigbeeDevice); foreach (var automation in automations) { // todo check if not null and if more than one element if (zigbeeDevice != null && automation.Triggers.Any(t => t.DeviceId == zigbeeDevice.Id)) { System.Console.WriteLine($"Open automation {automation.Name}"); var automationTrigger = automation.Triggers.Where(t => t.DeviceId == zigbeeDevice.Id).FirstOrDefault(); System.Type type = deserializedReceivedMessage.GetType(); PropertyInfo property = type.GetProperty(automationTrigger.StateName); triggerStateValueCheck = property.GetValue(deserializedReceivedMessage); triggerStateName = property.Name; if (automationTrigger.StateName == triggerStateName && automationTrigger.StateValue.ToLower() == triggerStateValueCheck.ToString().ToLower()) { // Todo check condition if (automation.Conditions.Count <= 0) { System.Console.WriteLine("None conditions"); foreach (var action in automation.Actions) { System.Console.WriteLine($"Check Action ! {action.StateName} {action.StateValue}"); var stateName = action.StateName; var stateValue = action.StateValue; 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={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) { case "zigbee2mqtt": Zigbee2MqttRequest zigbee2MqttRequest = new Zigbee2MqttRequest() { }; var actionRequest = ""; // If the state is already good, do not send the request. (in order to not spam mqtt broker) bool alreadyInAskedState = false; System.Console.WriteLine($"zigbee2mqtt type !"); // TODO: GET AND CHECK DEVICE ACTION POSSIBILITIES // TODO: Check state name (state, action.. ) 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) { var deserializedLastState = JsonConvert.DeserializeObject(actionDeviceToTest.LastState); if (stateValue == DeviceAction.toggle.ToString()) { System.Console.WriteLine($"Toggle action"); // TO CHECK switch (deserializedLastState.state) { case "ON": actionRequest = "OFF"; zigbee2MqttRequest.brightness = 0; break; case "OFF": case null: default: actionRequest = "ON"; zigbee2MqttRequest.brightness = 255; break; } } else if (stateValue.ToLower() == DeviceAction.on.ToString().ToLower()) { // retrieve device state to check if already in asked state if (deserializedLastState.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; else { actionRequest = "OFF"; zigbee2MqttRequest.brightness = 0; } } } if (!alreadyInAskedState) { System.Console.WriteLine($"Before retrieving type etc {zigbee2MqttRequest.state}"); System.Type type2 = zigbee2MqttRequest.GetType(); PropertyInfo property2 = type2.GetProperty(stateName); property2.SetValue(zigbee2MqttRequest, actionRequest, null); var request = JsonConvert.SerializeObject(zigbee2MqttRequest); System.Console.WriteLine($"Send request ! zigbee2mqtt/{actionName}/set/{request}"); MqttClientService.PublishMessage("zigbee2mqtt/" + actionName + "/set", request); } break; case "meross": System.Console.WriteLine($"meross type !"); break; } } } } } } } else { // do nothing is a set } } catch (Exception ex) { } } // switch case according to device type (topic !) if (topicSplit[1].Contains("MagicCube0")) { var test = JsonConvert.DeserializeObject(message); /*if (test.Action == "shake") { if (YeelightService.devices.Count <= 0) { await YeelightService.GetDevices(); } var labLamp = YeelightService.devices.Where(d => d.Hostname == "192.168.31.74").FirstOrDefault(); if (labLamp != null) { Task.Run(async () => { await YeelightService.Toggle(labLamp); }); } }*/ /* if (test.action == "shake") { // TODO Check state Zigbee2MqttRequest zigbee2MqttRequest = new Zigbee2MqttRequest() { state = "OFF", brightness = 0 }; var request = JsonConvert.SerializeObject(zigbee2MqttRequest); MqttClientService.PublishMessage("zigbee2mqtt/GU10Bureau/set", request); }*/ if (test.action == "tap") { 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(); if (multiprise != null) { //As multisocket channel 0 is all the sockets, skip 0 var tests = actionTime - lastActionTime; if (tests >= 1000) { isOpen = !isOpen; if (isOpen) { /*foreach (var channel in multiprise.channels) { if (i != 0) MqttClientMerossService.ExecuteCommand(multiprise.ServiceIdentification, Method.SET, CommandMqtt.TOGGLEX, "", "", ToggleStatus.OFF, i); i++; }*/ MqttClientMerossService.ExecuteCommand(multiprise.ServiceIdentification, Method.SET, CommandMqtt.TOGGLEX, "", "", ToggleStatus.ON, 1); /*MqttClientMerossService.ExecuteCommand(multiprise.ServiceIdentification, Method.SET, CommandMqtt.TOGGLEX, "", "", ToggleStatus.ON, 2); MqttClientMerossService.ExecuteCommand(multiprise.ServiceIdentification, Method.SET, CommandMqtt.TOGGLEX, "", "", ToggleStatus.ON, 3);*/ //MqttClientMerossService.ExecuteCommand(prise.ServiceIdentification, Method.SET, CommandMqtt.TOGGLEX, "", "", ToggleStatus.ON, 0); } else { MqttClientMerossService.ExecuteCommand(multiprise.ServiceIdentification, Method.SET, CommandMqtt.TOGGLEX, "", "", ToggleStatus.OFF, 1); /*MqttClientMerossService.ExecuteCommand(multiprise.ServiceIdentification, Method.SET, CommandMqtt.TOGGLEX, "", "", ToggleStatus.OFF, 2); MqttClientMerossService.ExecuteCommand(multiprise.ServiceIdentification, Method.SET, CommandMqtt.TOGGLEX, "", "", ToggleStatus.OFF, 3);*/ //MqttClientMerossService.ExecuteCommand(prise.ServiceIdentification, Method.SET, CommandMqtt.TOGGLEX, "", "", ToggleStatus.OFF, 0); } } lastActionTime = actionTime; } /*if (lightStateIkeaBulb == LightState.Undefined || lightStateIkeaBulb == LightState.Off) PublishMessage("zigbee2mqtt/0x14b457fffe7628fa/set", "{\"state\": \"ON\"}"); else PublishMessage("zigbee2mqtt/0x14b457fffe7628fa/set", "{\"state\": \"OFF\"}");*/ } //await MqttClientOnlineService.PublishMessage("Notification", "Hey magic cube 0 !"); } break; default: 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>(message); var zigbee2mqttProvider = _ProviderDatabaseService.GetByType("zigbee2mqtt"); if (zigbee2mqttProvider != null) { // Retrieve existing devices List 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> 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>(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) // TODO : wait for new devices // GroupService.CompareGroupsFromZigbee2Mqtt(userId, groups, groupsConvert, _DeviceDatabaseService, _GroupDatabaseService); } } catch (Exception ex) { Console.WriteLine($"Error during retrieving groups ! Exception: {ex}"); } break; } } } }