372 lines
24 KiB
C#

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 triggerStateValue;
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, 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) // 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 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<AqaraCube>(message);
zigbeeDevice.LastState = message;
break;
case DeviceType.Light:
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;
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;
// Todo check state name and value for triggers..
if (automationTrigger.StateName == triggerStateName && automationTrigger.StateValue == triggerStateValueCheck.ToString())
{
// Todo check condition
if (automation.Conditions.Count <= 0)
{
System.Console.WriteLine("None conditions");
// => SEND REQUEST
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 = "";
System.Console.WriteLine($"zigbee2mqtt type !");
// Todo GET AND CHECK DEVICE ACTION POSSIBLE
// todo check state name (state, action.. )
System.Console.WriteLine($"actionDeviceToTest.Type {actionDeviceToTest.Type}");
if (actionDeviceToTest.Type == DeviceType.Light)
{
var deserializedReceivedMessage2 = JsonConvert.DeserializeObject<LightBulb>(actionDeviceToTest.LastState);
if (stateValue == DeviceAction.toggle.ToString())
{
System.Console.WriteLine($"Toggle action");
// TO CHECK
switch (deserializedReceivedMessage2.state)
{
case "ON":
actionRequest = "OFF";
zigbee2MqttRequest.brightness = 0;
break;
case "OFF":
case null:
default:
actionRequest = "ON";
zigbee2MqttRequest.brightness = 255;
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}");
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<AqaraCube>(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 !");
}
if (topicSplit[1].Contains("MotionWC"))
{
var aqaraSwitch = JsonConvert.DeserializeObject<AqaraMotion>(message);
if (aqaraSwitch.occupancy)
{
Zigbee2MqttRequest zigbee2MqttRequest = new Zigbee2MqttRequest() { state = "ON" };
var request = JsonConvert.SerializeObject(zigbee2MqttRequest);
MqttClientService.PublishMessage("zigbee2mqtt/LampeWC/set", request);
}
else {
/*Zigbee2MqttRequest zigbee2MqttRequest = new Zigbee2MqttRequest() { state = "OFF" };
var request = JsonConvert.SerializeObject(zigbee2MqttRequest);
MqttClientService.PublishMessage("zigbee2mqtt/LampeWC/set", request);*/
}
}
if (topicSplit[1].Contains("Motion0"))
{
var aqaraMotion = JsonConvert.DeserializeObject<AqaraMotion>(message);
if (aqaraMotion.occupancy)
{
Zigbee2MqttRequest zigbee2MqttRequest = new Zigbee2MqttRequest() { state = "ON", brightness = 255 };
var request = JsonConvert.SerializeObject(zigbee2MqttRequest);
MqttClientService.PublishMessage("zigbee2mqtt/GU10Bureau/set", request);
}
else
{
/*Zigbee2MqttRequest zigbee2MqttRequest = new Zigbee2MqttRequest() { state = "OFF", brightness = 0 };
var request = JsonConvert.SerializeObject(zigbee2MqttRequest);
MqttClientService.PublishMessage("zigbee2mqtt/GU10Bureau/set", request);*/
}
}
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<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;
}
}
}
}